diff --git a/base_requirements.txt b/base_requirements.txt index 75ee4bbfd37..7eaa9d9285f 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -1,6 +1,6 @@ # The Python web framework on which NetBox is built # https://docs.djangoproject.com/en/stable/releases/ -Django<5.2 +Django==5.2.* # Django middleware which permits cross-domain API requests # https://github.com/adamchainz/django-cors-headers/blob/main/CHANGELOG.rst @@ -42,6 +42,10 @@ django-rich # https://github.com/rq/django-rq/blob/master/CHANGELOG.md django-rq +# Provides a variety of storage backends +# https://github.com/jschneier/django-storages/blob/master/CHANGELOG.rst +django-storages + # Abstraction models for rendering and paginating HTML tables # https://github.com/jieter/django-tables2/blob/master/CHANGELOG.md django-tables2 @@ -78,6 +82,10 @@ gunicorn # https://jinja.palletsprojects.com/changes/ Jinja2 +# JSON schema validation +# https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst +jsonschema + # Simple markup language for rendering HTML # https://python-markdown.github.io/changelog/ Markdown diff --git a/docs/administration/replicating-netbox.md b/docs/administration/replicating-netbox.md index 7cc4d38320f..f702c3ffd71 100644 --- a/docs/administration/replicating-netbox.md +++ b/docs/administration/replicating-netbox.md @@ -54,7 +54,7 @@ pg_dump --username netbox --password --host localhost -s netbox > netbox_schema. By default, NetBox stores uploaded files (such as image attachments) in its media directory. To fully replicate an instance of NetBox, you'll need to copy both the database and the media files. !!! note - These operations are not necessary if your installation is utilizing a [remote storage backend](../configuration/system.md#storage_backend). + These operations are not necessary if your installation is utilizing a [remote storage backend](../configuration/system.md#storages). ### Archive the Media Directory diff --git a/docs/configuration/plugins.md b/docs/configuration/plugins.md index a3e691f6394..765c3d50f6c 100644 --- a/docs/configuration/plugins.md +++ b/docs/configuration/plugins.md @@ -33,3 +33,21 @@ Note that a plugin must be listed in `PLUGINS` for its configuration to take eff --- +## PLUGINS_CATALOG_CONFIG + +Default: Empty + +This parameter controls how individual plugins are displayed in the plugins catalog under Admin > System > Plugins. Adding a plugin to the `hidden` list will omit that plugin from the catalog. Adding a plugin to the `static` list will display the plugin, but not link to the plugin details or upgrade instructions. + +An example configuration is shown below: + +```python +PLUGINS_CATALOG_CONFIG = { + 'hidden': [ + 'plugin1', + ], + 'static': [ + 'plugin2', + ], +} +``` diff --git a/docs/configuration/required-parameters.md b/docs/configuration/required-parameters.md index f7e5d71ce1f..4a18e8a6c0b 100644 --- a/docs/configuration/required-parameters.md +++ b/docs/configuration/required-parameters.md @@ -25,7 +25,30 @@ ALLOWED_HOSTS = ['*'] ## DATABASE -NetBox requires access to a PostgreSQL 13 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary: +!!! warning "Legacy Configuration Parameter" + The `DATABASE` configuration parameter is deprecated and will be removed in a future release. Users are advised to adopt the new `DATABASES` (plural) parameter, which allows for the configuration of multiple databases. + +See the [`DATABASES`](#databases) configuration below for usage. + +--- + +## DATABASES + +!!! info "This parameter was introduced in NetBox v4.3." + +NetBox requires access to a PostgreSQL 14 or later database service to store data. This service can run locally on the NetBox server or on a remote system. Databases are defined as named dictionaries: + +```python +DATABASES = { + 'default': {...}, + 'external1': {...}, + 'external2': {...}, +} +``` + +NetBox itself requires only that a `default` database is defined. However, certain plugins may require the configuration of additional databases. (Consider also configuring the [`DATABASE_ROUTERS`](./system.md#database_routers) parameter when multiple databases are in use.) + +The following parameters must be defined for each database: * `NAME` - Database name * `USER` - PostgreSQL username @@ -38,14 +61,16 @@ NetBox requires access to a PostgreSQL 13 or later database service to store dat Example: ```python -DATABASE = { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'netbox', # Database name - 'USER': 'netbox', # PostgreSQL username - 'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password - 'HOST': 'localhost', # Database server - 'PORT': '', # Database port (leave blank for default) - 'CONN_MAX_AGE': 300, # Max database connection age +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'netbox', # Database name + 'USER': 'netbox', # PostgreSQL username + 'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password + 'HOST': 'localhost', # Database server + 'PORT': '', # Database port (leave blank for default) + 'CONN_MAX_AGE': 300, # Max database connection age + } } ``` @@ -53,7 +78,7 @@ DATABASE = { NetBox supports all PostgreSQL database options supported by the underlying Django framework. For a complete list of available parameters, please see [the Django documentation](https://docs.djangoproject.com/en/stable/ref/settings/#databases). !!! warning - Make sure to use a PostgreSQL-compatible backend for the ENGINE setting. If you don't specify an ENGINE, the default will be django.db.backends.postgresql. + The `ENGINE` parameter must specify a PostgreSQL-compatible database backend. If not defined, the default engine `django.db.backends.postgresql` will be used. --- diff --git a/docs/configuration/security.md b/docs/configuration/security.md index b97f3143205..950d2df34bf 100644 --- a/docs/configuration/security.md +++ b/docs/configuration/security.md @@ -2,7 +2,10 @@ ## ALLOW_TOKEN_RETRIEVAL -Default: True +Default: False + +!!! note + The default value of this parameter changed from true to false in NetBox v4.3.0. If disabled, the values of API tokens will not be displayed after each token's initial creation. A user **must** record the value of a token prior to its creation, or it will be lost. Note that this affects _all_ users, regardless of assigned permissions. @@ -186,6 +189,17 @@ The lifetime (in seconds) of the authentication cookie issued to a NetBox user u --- +## LOGIN_FORM_HIDDEN + +Default: False + +Option to hide the login form when only SSO authentication is in use. + +!!! warning + If the SSO provider is unreachable, login to NetBox will be impossible if this option is enabled. The only recourse is to disable it in the local configuration and restart the NetBox service. + +--- + ## LOGOUT_REDIRECT_URL Default: `'home'` diff --git a/docs/configuration/system.md b/docs/configuration/system.md index af3a6f5e6f4..11db0937044 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -12,6 +12,14 @@ BASE_PATH = 'netbox/' --- +## DATABASE_ROUTERS + +Default: `[]` (empty list) + +An iterable of [database routers](https://docs.djangoproject.com/en/stable/topics/db/multi-db/) to use for automatically selecting the appropriate database(s) for a query. This is useful only when [multiple databases](./required-parameters.md#databases) have been configured. + +--- + ## DEFAULT_LANGUAGE Default: `en-us` (US English) @@ -64,7 +72,7 @@ Email is sent from NetBox only for critical events or if configured for [logging ## HTTP_PROXIES -Default: None +Default: Empty A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies). For example: @@ -75,6 +83,8 @@ HTTP_PROXIES = { } ``` +If more flexibility is needed in determining which proxy to use for a given request, consider implementing one or more custom proxy routers via the [`PROXY_ROUTERS`](#proxy_routers) parameter. + --- ## INTERNAL_IPS @@ -160,6 +170,16 @@ The file path to the location where media files (such as image attachments) are --- +## PROXY_ROUTERS + +Default: `["utilities.proxy.DefaultProxyRouter"]` + +A list of Python classes responsible for determining which proxy server(s) to use for outbound HTTP requests. Each item in the list can be the class itself or the dotted path to the class. + +The `route()` method on each class must return a dictionary of candidate proxies arranged by protocol (e.g. `http` and/or `https`), or None if no viable proxy can be determined. The default class, `DefaultProxyRouter`, simply returns the content of [`HTTP_PROXIES`](#http_proxies). + +--- + ## REPORTS_ROOT Default: `$INSTALL_ROOT/netbox/reports/` @@ -184,23 +204,46 @@ The dotted path to the desired search backend class. `CachedValueSearchBackend` --- -## STORAGE_BACKEND +## STORAGES -Default: None (local storage) +The backend storage engine for handling uploaded files such as [image attachments](../models/extras/imageattachment.md) and [custom scripts](../customization/custom-scripts.md). NetBox integrates with the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) and [`django-storage-swift`](https://github.com/dennisv/django-storage-swift) libraries, which provide backends for several popular file storage services. If not configured, local filesystem storage will be used. -The backend storage engine for handling uploaded files (e.g. image attachments). NetBox supports integration with the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) and [`django-storage-swift`](https://github.com/dennisv/django-storage-swift) packages, which provide backends for several popular file storage services. If not configured, local filesystem storage will be used. +By default, the following configuration is used: -The configuration parameters for the specified storage backend are defined under the `STORAGE_CONFIG` setting. +```python +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, + "scripts": { + "BACKEND": "extras.storage.ScriptFileSystemStorage", + }, +} +``` ---- +Within the `STORAGES` dictionary, `"default"` is used for image uploads, "staticfiles" is for static files and `"scripts"` is used for custom scripts. -## STORAGE_CONFIG +If using a remote storage like S3, define the config as `STORAGES[key]["OPTIONS"]` for each storage item as needed. For example: -Default: Empty +```python +STORAGES = { + "scripts": { + "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", + "OPTIONS": { + 'access_key': 'access key', + 'secret_key': 'secret key', + } + }, +} +``` -A dictionary of configuration parameters for the storage backend configured as `STORAGE_BACKEND`. The specific parameters to be used here are specific to each backend; see the documentation for your selected backend ([`django-storages`](https://django-storages.readthedocs.io/en/stable/) or [`django-storage-swift`](https://github.com/dennisv/django-storage-swift)) for more detail. +The specific configuration settings for each storage backend can be found in the [django-storages documentation](https://django-storages.readthedocs.io/en/latest/index.html). -If `STORAGE_BACKEND` is not defined, this setting will be ignored. +!!! note + Any keys defined in the `STORAGES` configuration parameter replace those in the default configuration. It is only necessary to define keys within the `STORAGES` for the specific backend(s) you wish to configure. --- diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 1051b31f671..56dd08a7668 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -140,6 +140,8 @@ The Script class provides two convenience methods for reading data from files: These two methods will load data in YAML or JSON format, respectively, from files within the local path (i.e. `SCRIPTS_ROOT`). +**Note:** These convenience methods are deprecated and will be removed in NetBox v4.4. These only work if running scripts within the local path, they will not work if using a storage other than ScriptFileSystemStorage. + ## Logging The Script object provides a set of convenient functions for recording messages at different severity levels: diff --git a/docs/development/adding-models.md b/docs/development/adding-models.md index 0bf02066268..da0e49511a3 100644 --- a/docs/development/adding-models.md +++ b/docs/development/adding-models.md @@ -76,11 +76,13 @@ Create the following for each model: ## 13. GraphQL API components -Create a GraphQL object type for the model in `graphql/types.py` by subclassing the appropriate class from `netbox.graphql.types`. +Create the following for each model: -**Note:** GraphQL unit tests may fail citing null values on a non-nullable field if related objects are prefetched. You may need to fix this by setting the type annotation to be `= strawberry_django.field(select_related=["policy"])` or similar. +* GraphQL object type for the model in `graphql/types.py` (subclass the appropriate class from `netbox.graphql.types`) +* Add a GraphQL filter for the model in `graphql/filters.py` +* Extend the query class for the app in `graphql/schema.py` with the individual object and object list fields -Also extend the schema class defined in `graphql/schema.py` with the individual object and object list fields per the established convention. +**Note:** GraphQL unit tests may fail citing null values on a non-nullable field if related objects are prefetched. You may need to fix this by setting the type annotation to be `= strawberry_django.field(select_related=["foo"])` or similar. ## 14. Add tests diff --git a/docs/development/extending-models.md b/docs/development/extending-models.md index 16d1c345144..d870a371d65 100644 --- a/docs/development/extending-models.md +++ b/docs/development/extending-models.md @@ -6,7 +6,7 @@ Below is a list of tasks to consider when adding a new field to a core model. Add the field to the model, taking care to address any of the following conditions. -* When adding a GenericForeignKey field, also add an index under `Meta` for its two concrete fields. For example: +* When adding a GenericForeignKey field, you may need add an index under `Meta` for its two concrete fields. (This is required only for non-unique GFK relationships, as the unique constraint introduces its own index.) For example: ```python class Meta: diff --git a/docs/development/getting-started.md b/docs/development/getting-started.md index 0b77bfd4dac..129bf2d4b6a 100644 --- a/docs/development/getting-started.md +++ b/docs/development/getting-started.md @@ -115,7 +115,7 @@ You may also need to set up the yarn packages as shown in the [Web UI Developmen Within the `netbox/netbox/` directory, copy `configuration_example.py` to `configuration.py` and update the following parameters: * `ALLOWED_HOSTS`: This can be set to `['*']` for development purposes -* `DATABASE`: PostgreSQL database connection parameters +* `DATABASES`: PostgreSQL database connection parameters * `REDIS`: Redis configuration (if different from the defaults) * `SECRET_KEY`: Set to a random string (use `generate_secret_key.py` in the parent directory to generate a suitable key) * `DEBUG`: Set to `True` diff --git a/docs/installation/1-postgresql.md b/docs/installation/1-postgresql.md index 8ba302909a1..536ecea6482 100644 --- a/docs/installation/1-postgresql.md +++ b/docs/installation/1-postgresql.md @@ -2,8 +2,8 @@ This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md). -!!! warning "PostgreSQL 13 or later required" - NetBox requires PostgreSQL 13 or later. Please note that MySQL and other relational databases are **not** supported. +!!! warning "PostgreSQL 14 or later required" + NetBox requires PostgreSQL 14 or later. Please note that MySQL and other relational databases are **not** supported. ## Installation @@ -34,7 +34,7 @@ This section entails the installation and configuration of a local PostgreSQL da sudo systemctl enable --now postgresql ``` -Before continuing, verify that you have installed PostgreSQL 13 or later: +Before continuing, verify that you have installed PostgreSQL 14 or later: ```no-highlight psql -V diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 60d60d4f0cc..33eef6057a8 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -128,7 +128,7 @@ sudo cp configuration_example.py configuration.py Open `configuration.py` with your preferred editor to begin configuring NetBox. NetBox offers [many configuration parameters](../configuration/index.md), but only the following four are required for new installations: * `ALLOWED_HOSTS` -* `DATABASE` +* `DATABASES` (or `DATABASE`) * `REDIS` * `SECRET_KEY` @@ -146,18 +146,22 @@ If you are not yet sure what the domain name and/or IP address of the NetBox ins ALLOWED_HOSTS = ['*'] ``` -### DATABASE +### DATABASES -This parameter holds the database configuration details. You must define the username and password used when you configured PostgreSQL. If the service is running on a remote host, update the `HOST` and `PORT` parameters accordingly. See the [configuration documentation](../configuration/required-parameters.md#database) for more detail on individual parameters. +This parameter holds the PostgreSQL database configuration details. The default database must be defined; additional databases may be defined as needed e.g. by plugins. + +A username and password must be defined for the default database. If the service is running on a remote host, update the `HOST` and `PORT` parameters accordingly. See the [configuration documentation](../configuration/required-parameters.md#databases) for more detail on individual parameters. ```python -DATABASE = { - 'NAME': 'netbox', # Database name - 'USER': 'netbox', # PostgreSQL username - 'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password - 'HOST': 'localhost', # Database server - 'PORT': '', # Database port (leave blank for default) - 'CONN_MAX_AGE': 300, # Max database connection age (seconds) +DATABASES = { + 'default': { + 'NAME': 'netbox', # Database name + 'USER': 'netbox', # PostgreSQL username + 'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password + 'HOST': 'localhost', # Database server + 'PORT': '', # Database port (leave blank for default) + 'CONN_MAX_AGE': 300, # Max database connection age (seconds) + } } ``` @@ -207,7 +211,7 @@ All Python packages required by NetBox are listed in `requirements.txt` and will ### Remote File Storage -By default, NetBox will use the local filesystem to store uploaded files. To use a remote filesystem, install the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) library and configure your [desired storage backend](../configuration/system.md#storage_backend) in `configuration.py`. +By default, NetBox will use the local filesystem to store uploaded files. To use a remote filesystem, install the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) library and configure your [desired storage backend](../configuration/system.md#storages) in `configuration.py`. ```no-highlight sudo sh -c "echo 'django-storages' >> /opt/netbox/local_requirements.txt" diff --git a/docs/installation/index.md b/docs/installation/index.md index 33888e27420..24e966805bb 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -21,7 +21,7 @@ The following sections detail how to set up a new instance of NetBox: | Dependency | Supported Versions | |------------|--------------------| | Python | 3.10, 3.11, 3.12 | -| PostgreSQL | 13+ | +| PostgreSQL | 14+ | | Redis | 4.0+ | Below is a simplified overview of the NetBox application stack for reference: diff --git a/docs/installation/upgrading.md b/docs/installation/upgrading.md index e6d05738f42..07250e780af 100644 --- a/docs/installation/upgrading.md +++ b/docs/installation/upgrading.md @@ -20,7 +20,7 @@ NetBox requires the following dependencies: | Dependency | Supported Versions | |------------|--------------------| | Python | 3.10, 3.11, 3.12 | -| PostgreSQL | 13+ | +| PostgreSQL | 14+ | | Redis | 4.0+ | ## 3. Install the Latest Release diff --git a/docs/integrations/graphql-api.md b/docs/integrations/graphql-api.md index c02045f347b..cae046b6c4d 100644 --- a/docs/integrations/graphql-api.md +++ b/docs/integrations/graphql-api.md @@ -11,7 +11,7 @@ curl -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ http://netbox/graphql/ \ ---data '{"query": "query {circuit_list(status:\"active\") {cid provider {name}}}"}' +--data '{"query": "query {circuit_list(filters:{status: STATUS_ACTIVE}) {cid provider {name}}}"}' ``` The response will include the requested data formatted as JSON: @@ -51,19 +51,48 @@ For more detail on constructing GraphQL queries, see the [GraphQL queries docume ## Filtering -The GraphQL API employs the same filtering logic as the UI and REST API. Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only sites within the North Carolina region with a status of active: +!!! note "Changed in NetBox v4.3" + The filtering syntax fo the GraphQL API has changed substantially in NetBox v4.3. + +Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only active sites: ``` query { - site_list(filters: {region: "us-nc", status: "active"}) { + site_list( + filters: { + status: STATUS_ACTIVE + } + ) { name } } ``` -In addition, filtering can be done on list of related objects as shown in the following query: + +Filters can be combined with logical operators, such as `OR` and `NOT`. For example, the following will return every site that is planned _or_ assigned to a tenant named Foo: ``` -{ +query { + site_list( + filters: { + status: STATUS_PLANNED, + OR: { + tenant: { + name: { + exact: "Foo" + } + } + } + } + ) { + name + } +} +``` + +Filtering can also be applied to related objects. For example, the following query will return only enabled interfaces for each device: + +``` +query { device_list { id name @@ -102,6 +131,18 @@ Certain queries can return multiple types of objects, for example cable terminat ``` The field "class_type" is an easy way to distinguish what type of object it is when viewing the returned data, or when filtering. It contains the class name, for example "CircuitTermination" or "ConsoleServerPort". +## Pagination + +Queries can be paginated by specifying pagination in the query and supplying an offset and optionaly a limit in the query. If no limit is given, a default of 100 is used. Queries are not paginated unless requested in the query. An example paginated query is shown below: + +``` +query { + device_list(pagination: { offset: 0, limit: 20 }) { + id + } +} +``` + ## Authentication NetBox's GraphQL API uses the same API authentication tokens as its REST API. Authentication tokens are included with requests by attaching an `Authorization` HTTP header in the following form: diff --git a/docs/introduction.md b/docs/introduction.md index 75701c119f7..c8e5ee8ac39 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -79,5 +79,5 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and | HTTP service | nginx or Apache | | WSGI service | gunicorn or uWSGI | | Application | Django/Python | -| Database | PostgreSQL 13+ | +| Database | PostgreSQL 14+ | | Task queuing | Redis/django-rq | diff --git a/docs/models/core/datasource.md b/docs/models/core/datasource.md index 0e18a2aae10..527d93939d1 100644 --- a/docs/models/core/datasource.md +++ b/docs/models/core/datasource.md @@ -44,6 +44,12 @@ A set of rules (one per line) identifying filenames to ignore during synchroniza | `*.txt` | Ignore any files with a `.txt` extension | | `data???.json` | Ignore e.g. `data123.json` | +### Sync Interval + +!!! info "This field was introduced in NetBox v4.3." + +The interval at which the data source should automatically synchronize. If not set, the data source must be synchronized manually. + ### Last Synced The date and time at which the source was most recently synchronized successfully. diff --git a/docs/models/dcim/devicerole.md b/docs/models/dcim/devicerole.md index 786170f2bc8..e58373565c9 100644 --- a/docs/models/dcim/devicerole.md +++ b/docs/models/dcim/devicerole.md @@ -4,6 +4,10 @@ Devices can be organized by functional roles, which are fully customizable by th ## Fields +### Parent + +The parent role of which this role is a child (optional). + ### Name A unique human-friendly name. diff --git a/docs/models/dcim/inventoryitem.md b/docs/models/dcim/inventoryitem.md index 2d648341baa..6aed0fc86ec 100644 --- a/docs/models/dcim/inventoryitem.md +++ b/docs/models/dcim/inventoryitem.md @@ -1,5 +1,8 @@ # Inventory Items +!!! warning "Deprecation Warning" + Beginning in NetBox v4.3, the use of inventory items has been deprecated. They are planned for removal in a future NetBox release. Users are strongly encouraged to begin using [modules](./module.md) and [module types](./moduletype.md) in place of inventory items. Modules provide enhanced functionality and can be configured with user-defined attributes. + Inventory items represent hardware components installed within a device, such as a power supply or CPU or line card. They are intended to be used primarily for inventory purposes. Inventory items are hierarchical in nature, such that any individual item may be designated as the parent for other items. For example, an inventory item might be created to represent a line card which houses several SFP optics, each of which exists as a child item within the device. An inventory item may also be associated with a specific component within the same device. For example, you may wish to associate a transceiver with an interface. diff --git a/docs/models/dcim/inventoryitemrole.md b/docs/models/dcim/inventoryitemrole.md index 50eb61abd32..b776376044a 100644 --- a/docs/models/dcim/inventoryitemrole.md +++ b/docs/models/dcim/inventoryitemrole.md @@ -1,5 +1,8 @@ # Inventory Item Roles +!!! warning "Deprecation Warning" + Beginning in NetBox v4.3, the use of inventory items has been deprecated. They are planned for removal in a future NetBox release. Users are strongly encouraged to begin using [modules](./module.md) and [module types](./moduletype.md) in place of inventory items. Modules provide enhanced functionality and can be configured with user-defined attributes. + Inventory items can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for power supplies, fans, interface optics, etc. ## Fields diff --git a/docs/models/dcim/inventoryitemtemplate.md b/docs/models/dcim/inventoryitemtemplate.md index 02fde599564..7d8ff504d70 100644 --- a/docs/models/dcim/inventoryitemtemplate.md +++ b/docs/models/dcim/inventoryitemtemplate.md @@ -1,3 +1,6 @@ # Inventory Item Templates +!!! warning "Deprecation Warning" + Beginning in NetBox v4.3, the use of inventory items has been deprecated. They are planned for removal in a future NetBox release. Users are strongly encouraged to begin using [modules](./module.md) and [module types](./moduletype.md) in place of inventory items. Modules provide enhanced functionality and can be configured with user-defined attributes. + A template for an inventory item that will be automatically created when instantiating a new device. All attributes of this object will be copied to the new inventory item, including the associations with a parent item and assigned component, if any. See the [inventory item](./inventoryitem.md) documentation for more detail. diff --git a/docs/models/dcim/moduletype.md b/docs/models/dcim/moduletype.md index 7077e16c245..88f04466a3e 100644 --- a/docs/models/dcim/moduletype.md +++ b/docs/models/dcim/moduletype.md @@ -43,3 +43,11 @@ The numeric weight of the module, including a unit designation (e.g. 3 kilograms ### Airflow The direction in which air circulates through the device chassis for cooling. + +### Profile + +The assigned [profile](./moduletypeprofile.md) for the type of module. Profiles can be used to classify module types by function (e.g. power supply, hard disk, etc.), and they support the addition of user-configurable attributes on module types. The assignment of a module type to a profile is optional. + +### Attributes + +Depending on the module type's assigned [profile](./moduletypeprofile.md) (if any), one or more user-defined attributes may be available to configure. diff --git a/docs/models/dcim/moduletypeprofile.md b/docs/models/dcim/moduletypeprofile.md new file mode 100644 index 00000000000..80345c82b5e --- /dev/null +++ b/docs/models/dcim/moduletypeprofile.md @@ -0,0 +1,40 @@ +# Module Type Profiles + +!!! info "This model was introduced in NetBox v4.3." + +Each [module type](./moduletype.md) may optionally be assigned a profile according to its classification. A profile can extend module types with user-configured attributes. For example, you might want to specify the input current and voltage of a power supply, or the clock speed and number of cores for a processor. + +Module type attributes are managed via the configuration of a [JSON schema](https://json-schema.org/) on the profile. For example, the following schema introduces three module type attributes, two of which are designated as required attributes. + +```json +{ + "properties": { + "type": { + "type": "string", + "title": "Disk type", + "enum": ["HD", "SSD", "NVME"], + "default": "HD" + }, + "capacity": { + "type": "integer", + "title": "Capacity (GB)", + "description": "Gross disk size" + }, + "speed": { + "type": "integer", + "title": "Speed (RPM)" + } + }, + "required": [ + "type", "capacity" + ] +} +``` + +The assignment of module types to a profile is optional. The designation of a schema for a profile is also optional: A profile can be used simply as a mechanism for classifying module types if the addition of custom attributes is not needed. + +## Fields + +### Schema + +This field holds the [JSON schema](https://json-schema.org/) for the profile. The configured JSON schema must be valid (or the field must be null). diff --git a/docs/models/dcim/poweroutlet.md b/docs/models/dcim/poweroutlet.md index a99f60b23ba..22a7ec63eb1 100644 --- a/docs/models/dcim/poweroutlet.md +++ b/docs/models/dcim/poweroutlet.md @@ -29,6 +29,19 @@ An alternative physical label identifying the power outlet. The type of power outlet. +### Status + +The operational status of the power outlet. By default, the following statuses are available: + +* Enabled +* Disabled +* Faulty + +!!! tip "Custom power outlet statuses" + Additional power outlet statuses may be defined by setting `PowerOutlet.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. + +!!! info "This field was introduced in NetBox v4.3." + ### Color !!! info "This field was introduced in NetBox v4.2." diff --git a/docs/models/dcim/racktype.md b/docs/models/dcim/racktype.md index b5f2d99e780..ecaf539c979 100644 --- a/docs/models/dcim/racktype.md +++ b/docs/models/dcim/racktype.md @@ -40,7 +40,7 @@ The number of the numerically lowest unit in the rack. This value defaults to on ### Outer Dimensions -The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches. +The external width, height and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches. ### Mounting Depth diff --git a/docs/models/extras/branch.md b/docs/models/extras/branch.md deleted file mode 100644 index 4599fed8599..00000000000 --- a/docs/models/extras/branch.md +++ /dev/null @@ -1,16 +0,0 @@ -# Branches - -!!! danger "Deprecated Feature" - This feature has been deprecated in NetBox v4.2 and will be removed in a future release. Please consider using the [netbox-branching plugin](https://github.com/netboxlabs/netbox-branching), which provides much more robust functionality. - -A branch is a collection of related [staged changes](./stagedchange.md) that have been prepared for merging into the active database. A branch can be merged by executing its `commit()` method. Deleting a branch will delete all its related changes. - -## Fields - -### Name - -The branch's name. - -### User - -The user to which the branch belongs (optional). diff --git a/docs/models/extras/configtemplate.md b/docs/models/extras/configtemplate.md index b580d688577..6b245e5e966 100644 --- a/docs/models/extras/configtemplate.md +++ b/docs/models/extras/configtemplate.md @@ -12,10 +12,6 @@ See the [configuration rendering documentation](../../features/configuration-ren A unique human-friendly name. -### Weight - -A numeric value which influences the order in which context data is merged. Contexts with a lower weight are merged before those with a higher weight. - ### Data File Template code may optionally be sourced from a remote [data file](../core/datafile.md), which is synchronized from a remote data source. When designating a data file, there is no need to specify template code: It will be populated automatically from the data file. @@ -27,3 +23,27 @@ Jinja2 template code, if being defined locally rather than replicated from a dat ### Environment Parameters A dictionary of any additional parameters to pass when instantiating the [Jinja2 environment](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment). Jinja2 supports various optional parameters which can be used to modify its default behavior. + +### MIME Type + +!!! info "This field was introduced in NetBox v4.3." + +The MIME type to indicate in the response when rendering the configuration template (optional). Defaults to `text/plain`. + +### File Name + +!!! info "This field was introduced in NetBox v4.3." + +The file name to give to the rendered export file (optional). + +### File Extension + +!!! info "This field was introduced in NetBox v4.3." + +The file extension to append to the file name in the response (optional). + +### As Attachment + +!!! info "This field was introduced in NetBox v4.3." + +If selected, the rendered content will be returned as a file attachment, rather than displayed directly in-browser (where supported). \ No newline at end of file diff --git a/docs/models/extras/exporttemplate.md b/docs/models/extras/exporttemplate.md index d2f9292c6e6..86e1ae04ac9 100644 --- a/docs/models/extras/exporttemplate.md +++ b/docs/models/extras/exporttemplate.md @@ -20,10 +20,20 @@ Template code may optionally be sourced from a remote [data file](../core/datafi Jinja2 template code for rendering the exported data. +### Environment Parameters + +!!! info "This field was introduced in NetBox v4.3." + +A dictionary of any additional parameters to pass when instantiating the [Jinja2 environment](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment). Jinja2 supports various optional parameters which can be used to modify its default behavior. + ### MIME Type The MIME type to indicate in the response when rendering the export template (optional). Defaults to `text/plain`. +### File Name + +The file name to give to the rendered export file (optional). + ### File Extension The file extension to append to the file name in the response (optional). diff --git a/docs/models/extras/stagedchange.md b/docs/models/extras/stagedchange.md deleted file mode 100644 index 0693a32d31d..00000000000 --- a/docs/models/extras/stagedchange.md +++ /dev/null @@ -1,29 +0,0 @@ -# Staged Changes - -!!! danger "Deprecated Feature" - This feature has been deprecated in NetBox v4.2 and will be removed in a future release. Please consider using the [netbox-branching plugin](https://github.com/netboxlabs/netbox-branching), which provides much more robust functionality. - -A staged change represents the creation of a new object or the modification or deletion of an existing object to be performed at some future point. Each change must be assigned to a [branch](./branch.md). - -Changes can be applied individually via the `apply()` method, however it is recommended to apply changes in bulk using the parent branch's `commit()` method. - -## Fields - -!!! warning - Staged changes are not typically created or manipulated directly, but rather effected through the use of the [`checkout()`](../../plugins/development/staged-changes.md) context manager. - -### Branch - -The [branch](./branch.md) to which this change belongs. - -### Action - -The type of action this change represents: `create`, `update`, or `delete`. - -### Object - -A generic foreign key referencing the existing object to which this change applies. - -### Data - -JSON representation of the changes being made to the object (not applicable for deletions). diff --git a/docs/models/extras/tag.md b/docs/models/extras/tag.md index 39de4826174..c4bc91b5a9a 100644 --- a/docs/models/extras/tag.md +++ b/docs/models/extras/tag.md @@ -16,6 +16,12 @@ A unique URL-friendly identifier. (This value will be used for filtering.) This The color to use when displaying the tag in the NetBox UI. +### Weight + +A numeric weight employed to influence the ordering of tags. Tags with a lower weight will be listed before those with higher weights. Values must be within the range **0** to **32767**. + +!!! info "This field was introduced in NetBox v4.3." + ### Object Types The assignment of a tag may be limited to a prescribed set of objects. For example, it may be desirable to limit the application of a specific tag to only devices and virtual machines. diff --git a/docs/models/ipam/iprange.md b/docs/models/ipam/iprange.md index 71f0884d9ce..fd439998a71 100644 --- a/docs/models/ipam/iprange.md +++ b/docs/models/ipam/iprange.md @@ -2,6 +2,12 @@ This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the `size` property on an IPRange instance.) Like [prefixes](./prefix.md) and [IP addresses](./ipaddress.md), each IP range may optionally be assigned to a [VRF](./vrf.md). +Each IP range can be marked as populated, which instructs NetBox to treat the range as though every IP address within it has been created (even though these individual IP addresses don't actually exist in the database). This can be helpful in scenarios where the management of a subset of IP addresses has been deferred to an external system of record, such as a DHCP server. NetBox will prohibit the creation of individual IP addresses within a range that has been marked as populated. + +An IP range can also be marked as utilized. This will cause its utilization to always be reported as 100% when viewing the range or when calculating the utilization of a parent prefix. (If not enabled, a range's utilization is calculated based on the number of IP addresses which have been created within it.) + +Typically, IP ranges marked as populated should also be marked as utilized, although there may be scenarios where this is undesirable (e.g. when reclaiming old IP space). An IP range which has been marked as populated but _not_ marked as utilized will always report a utilization of 0%, as it cannot contain child IP addresses. + ## Fields ### VRF @@ -29,6 +35,12 @@ The IP range's operational status. Note that the status of a range does _not_ ha !!! tip Additional statuses may be defined by setting `IPRange.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. +### Mark Populated + +!!! note "This field was added in NetBox v4.3." + +If enabled, NetBox will treat this IP range as being fully populated when calculating available IP space. It will also prevent the creation of IP addresses which fall within the declared range (and assigned VRF, if any). + ### Mark Utilized If enabled, the IP range will be considered 100% utilized regardless of how many IP addresses are defined within it. This is useful for documenting DHCP ranges, for example. diff --git a/docs/models/tenancy/contact.md b/docs/models/tenancy/contact.md index eac630180f0..f277ab4992d 100644 --- a/docs/models/tenancy/contact.md +++ b/docs/models/tenancy/contact.md @@ -4,9 +4,11 @@ A contact represents an individual or group that has been associated with an obj ## Fields -### Group +### Groups -The [contact group](./contactgroup.md) to which this contact is assigned (if any). +The [contact groups](./contactgroup.md) to which this contact is assigned (if any). + +!!! info "This field was renamed from `group` to `groups` in NetBox v4.3, and now supports the assignment of a contact to more than one group." ### Name diff --git a/docs/models/vpn/l2vpn.md b/docs/models/vpn/l2vpn.md index 1167c1c1780..983095ef866 100644 --- a/docs/models/vpn/l2vpn.md +++ b/docs/models/vpn/l2vpn.md @@ -33,6 +33,19 @@ The technology employed in forming and operating the L2VPN. Choices include: !!! note Designating the type as VPWS, EPL, EP-LAN, EP-TREE will limit the L2VPN instance to two terminations. +### Status + +The operational status of the L2VPN. By default, the following statuses are available: + +* Active (default) +* Planned +* Faulty + +!!! tip "Custom L2VPN statuses" + Additional L2VPN statuses may be defined by setting `L2VPN.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. + +!!! info "This field was introduced in NetBox v4.3." + ### Identifier An optional numeric identifier. This can be used to track a pseudowire ID, for example. diff --git a/docs/plugins/development/filtersets.md b/docs/plugins/development/filtersets.md index d803ce2f4b5..22480239733 100644 --- a/docs/plugins/development/filtersets.md +++ b/docs/plugins/development/filtersets.md @@ -1,6 +1,6 @@ # Filters & Filter Sets -Filter sets define the mechanisms available for filtering or searching through a set of objects in NetBox. For instance, sites can be filtered by their parent region or group, status, facility ID, and so on. The same filter set is used consistently for a model whether the request is made via the UI, REST API, or GraphQL API. NetBox employs the [django-filters2](https://django-tables2.readthedocs.io/en/latest/) library to define filter sets. +Filter sets define the mechanisms available for filtering or searching through a set of objects in NetBox. For instance, sites can be filtered by their parent region or group, status, facility ID, and so on. The same filter set is used consistently for a model whether the request is made via the UI or REST API. (Note that the GraphQL API uses a separate filter class.) NetBox employs the [django-filters2](https://django-tables2.readthedocs.io/en/latest/) library to define filter sets. ## FilterSet Classes diff --git a/docs/plugins/development/models.md b/docs/plugins/development/models.md index 03cedda1699..492b7fc9732 100644 --- a/docs/plugins/development/models.md +++ b/docs/plugins/development/models.md @@ -117,6 +117,8 @@ For more information about database migrations, see the [Django documentation](h ::: netbox.models.features.CloningMixin +::: netbox.models.features.ContactsMixin + ::: netbox.models.features.CustomLinksMixin ::: netbox.models.features.CustomFieldsMixin diff --git a/docs/plugins/development/staged-changes.md b/docs/plugins/development/staged-changes.md deleted file mode 100644 index a8fd1d232e0..00000000000 --- a/docs/plugins/development/staged-changes.md +++ /dev/null @@ -1,39 +0,0 @@ -# Staged Changes - -!!! danger "Deprecated Feature" - This feature has been deprecated in NetBox v4.2 and will be removed in a future release. Please consider using the [netbox-branching plugin](https://github.com/netboxlabs/netbox-branching), which provides much more robust functionality. - -NetBox provides a programmatic API to stage the creation, modification, and deletion of objects without actually committing those changes to the active database. This can be useful for performing a "dry run" of bulk operations, or preparing a set of changes for administrative approval, for example. - -To begin staging changes, first create a [branch](../../models/extras/branch.md): - -```python -from extras.models import Branch - -branch1 = Branch.objects.create(name='branch1') -``` - -Then, activate the branch using the `checkout()` context manager and begin making your changes. This initiates a new database transaction. - -```python -from extras.models import Branch -from netbox.staging import checkout - -branch1 = Branch.objects.get(name='branch1') -with checkout(branch1): - Site.objects.create(name='New Site', slug='new-site') - # ... -``` - -Upon exiting the context, the database transaction is automatically rolled back and your changes recorded as [staged changes](../../models/extras/stagedchange.md). Re-entering a branch will trigger a new database transaction and automatically apply any staged changes associated with the branch. - -To apply the changes within a branch, call the branch's `commit()` method: - -```python -from extras.models import Branch - -branch1 = Branch.objects.get(name='branch1') -branch1.commit() -``` - -Committing a branch is an all-or-none operation: Any exceptions will revert the entire set of changes. After successfully committing a branch, all its associated StagedChange objects are automatically deleted (however the branch itself will remain and can be reused). diff --git a/docs/plugins/development/views.md b/docs/plugins/development/views.md index e3740de596c..43cc0ce824b 100644 --- a/docs/plugins/development/views.md +++ b/docs/plugins/development/views.md @@ -198,6 +198,7 @@ Plugins can inject custom content into certain areas of core NetBox views. This | Method | View | Description | |---------------------|-------------|-----------------------------------------------------| +| `head()` | All | Custom HTML `` block includes | | `navbar()` | All | Inject content inside the top navigation bar | | `list_buttons()` | List view | Add buttons to the top of the page | | `buttons()` | Object view | Add buttons to the top of the page | diff --git a/mkdocs.yml b/mkdocs.yml index db6798eae40..f0bd9af7adc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -28,12 +28,7 @@ plugins: - mkdocstrings: handlers: python: - setup_commands: - - import os - - import django - - os.chdir('netbox/') - - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings") - - django.setup() + paths: ["netbox"] options: heading_level: 3 members_order: source @@ -150,7 +145,6 @@ nav: - GraphQL API: 'plugins/development/graphql-api.md' - Background Jobs: 'plugins/development/background-jobs.md' - Dashboard Widgets: 'plugins/development/dashboard-widgets.md' - - Staged Changes: 'plugins/development/staged-changes.md' - Exceptions: 'plugins/development/exceptions.md' - Migrating to v4.0: 'plugins/development/migration-v4.md' - Administration: @@ -226,7 +220,6 @@ nav: - VirtualDeviceContext: 'models/dcim/virtualdevicecontext.md' - Extras: - Bookmark: 'models/extras/bookmark.md' - - Branch: 'models/extras/branch.md' - ConfigContext: 'models/extras/configcontext.md' - ConfigTemplate: 'models/extras/configtemplate.md' - CustomField: 'models/extras/customfield.md' @@ -239,7 +232,6 @@ nav: - Notification: 'models/extras/notification.md' - NotificationGroup: 'models/extras/notificationgroup.md' - SavedFilter: 'models/extras/savedfilter.md' - - StagedChange: 'models/extras/stagedchange.md' - Subscription: 'models/extras/subscription.md' - Tag: 'models/extras/tag.md' - Webhook: 'models/extras/webhook.md' diff --git a/netbox/account/migrations/0001_initial.py b/netbox/account/migrations/0001_initial.py index 72c0795654d..badd459cacf 100644 --- a/netbox/account/migrations/0001_initial.py +++ b/netbox/account/migrations/0001_initial.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('users', '0004_netboxgroup_netboxuser'), + ('users', '0002_squashed_0004'), ] operations = [ diff --git a/netbox/account/views.py b/netbox/account/views.py index 05f40df3f00..3a2dc6b3280 100644 --- a/netbox/account/views.py +++ b/netbox/account/views.py @@ -89,10 +89,12 @@ class LoginView(View): if request.user.is_authenticated: logger = logging.getLogger('netbox.auth.login') return self.redirect_to_next(request, logger) + login_form_hidden = settings.LOGIN_FORM_HIDDEN return render(request, self.template_name, { 'form': form, 'auth_backends': self.get_auth_backends(request), + 'login_form_hidden': login_form_hidden, }) def post(self, request): diff --git a/netbox/circuits/graphql/enums.py b/netbox/circuits/graphql/enums.py new file mode 100644 index 00000000000..609e4435b95 --- /dev/null +++ b/netbox/circuits/graphql/enums.py @@ -0,0 +1,20 @@ +import strawberry + +from circuits.choices import * + +__all__ = ( + 'CircuitStatusEnum', + 'CircuitCommitRateEnum', + 'CircuitTerminationSideEnum', + 'CircuitTerminationPortSpeedEnum', + 'CircuitPriorityEnum', + 'VirtualCircuitTerminationRoleEnum', +) + + +CircuitCommitRateEnum = strawberry.enum(CircuitCommitRateChoices.as_enum()) +CircuitPriorityEnum = strawberry.enum(CircuitPriorityChoices.as_enum()) +CircuitStatusEnum = strawberry.enum(CircuitStatusChoices.as_enum()) +CircuitTerminationSideEnum = strawberry.enum(CircuitTerminationSideChoices.as_enum()) +CircuitTerminationPortSpeedEnum = strawberry.enum(CircuitTerminationPortSpeedChoices.as_enum()) +VirtualCircuitTerminationRoleEnum = strawberry.enum(VirtualCircuitTerminationRoleChoices.as_enum()) diff --git a/netbox/circuits/graphql/filter_mixins.py b/netbox/circuits/graphql/filter_mixins.py new file mode 100644 index 00000000000..3ae6fa82ea7 --- /dev/null +++ b/netbox/circuits/graphql/filter_mixins.py @@ -0,0 +1,19 @@ +from dataclasses import dataclass +from typing import Annotated, TYPE_CHECKING + +import strawberry +import strawberry_django + +from netbox.graphql.filter_mixins import OrganizationalModelFilterMixin + +if TYPE_CHECKING: + from netbox.graphql.enums import ColorEnum + +__all__ = ( + 'BaseCircuitTypeFilterMixin', +) + + +@dataclass +class BaseCircuitTypeFilterMixin(OrganizationalModelFilterMixin): + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() diff --git a/netbox/circuits/graphql/filters.py b/netbox/circuits/graphql/filters.py index 7d066f42860..48b4252ac42 100644 --- a/netbox/circuits/graphql/filters.py +++ b/netbox/circuits/graphql/filters.py @@ -1,7 +1,30 @@ -import strawberry_django +from datetime import date +from typing import Annotated, TYPE_CHECKING -from circuits import filtersets, models -from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin +import strawberry +import strawberry_django +from strawberry.scalars import ID +from strawberry_django import FilterLookup, DateFilterLookup + +from circuits import models +from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin +from dcim.graphql.filter_mixins import CabledObjectModelFilterMixin +from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin +from netbox.graphql.filter_mixins import ( + DistanceFilterMixin, + ImageAttachmentFilterMixin, + OrganizationalModelFilterMixin, + PrimaryModelFilterMixin, +) +from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin +from .filter_mixins import BaseCircuitTypeFilterMixin + +if TYPE_CHECKING: + from core.graphql.filters import ContentTypeFilter + from dcim.graphql.filters import InterfaceFilter + from ipam.graphql.filters import ASNFilter + from netbox.graphql.filter_lookups import IntegerLookup + from .enums import * __all__ = ( 'CircuitFilter', @@ -19,66 +42,160 @@ __all__ = ( @strawberry_django.filter(models.CircuitTermination, lookups=True) -@autotype_decorator(filtersets.CircuitTerminationFilterSet) -class CircuitTerminationFilter(BaseFilterMixin): - pass +class CircuitTerminationFilter( + BaseObjectTypeFilterMixin, + CustomFieldsFilterMixin, + TagsFilterMixin, + ChangeLogFilterMixin, + CabledObjectModelFilterMixin, +): + circuit: Annotated['CircuitFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + term_side: Annotated['CircuitTerminationSideEnum', strawberry.lazy('circuits.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + termination_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + termination_id: ID | None = strawberry_django.filter_field() + port_speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + upstream_speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + xconnect_id: FilterLookup[str] | None = strawberry_django.filter_field() + pp_info: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Circuit, lookups=True) -@autotype_decorator(filtersets.CircuitFilterSet) -class CircuitFilter(BaseFilterMixin): - pass +class CircuitFilter( + ContactFilterMixin, + ImageAttachmentFilterMixin, + DistanceFilterMixin, + TenancyFilterMixin, + PrimaryModelFilterMixin +): + cid: FilterLookup[str] | None = strawberry_django.filter_field() + provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_id: ID | None = strawberry_django.filter_field() + provider_account: Annotated['ProviderAccountFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_account_id: ID | None = strawberry_django.filter_field() + type: Annotated['CircuitTypeFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + type_id: ID | None = strawberry_django.filter_field() + status: Annotated['CircuitStatusEnum', strawberry.lazy('circuits.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + install_date: DateFilterLookup[date] | None = strawberry_django.filter_field() + termination_date: DateFilterLookup[date] | None = strawberry_django.filter_field() + commit_rate: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.CircuitType, lookups=True) -@autotype_decorator(filtersets.CircuitTypeFilterSet) -class CircuitTypeFilter(BaseFilterMixin): +class CircuitTypeFilter(BaseCircuitTypeFilterMixin): pass @strawberry_django.filter(models.CircuitGroup, lookups=True) -@autotype_decorator(filtersets.CircuitGroupFilterSet) -class CircuitGroupFilter(BaseFilterMixin): +class CircuitGroupFilter(TenancyFilterMixin, OrganizationalModelFilterMixin): pass @strawberry_django.filter(models.CircuitGroupAssignment, lookups=True) -@autotype_decorator(filtersets.CircuitGroupAssignmentFilterSet) -class CircuitGroupAssignmentFilter(BaseFilterMixin): - pass +class CircuitGroupAssignmentFilter( + BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin +): + member_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + member_id: ID | None = strawberry_django.filter_field() + group: Annotated['CircuitGroupFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + group_id: ID | None = strawberry_django.filter_field() + priority: Annotated['CircuitPriorityEnum', strawberry.lazy('circuits.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Provider, lookups=True) -@autotype_decorator(filtersets.ProviderFilterSet) -class ProviderFilter(BaseFilterMixin): - pass +class ProviderFilter(ContactFilterMixin, PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + asns: Annotated['ASNFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ProviderAccount, lookups=True) -@autotype_decorator(filtersets.ProviderAccountFilterSet) -class ProviderAccountFilter(BaseFilterMixin): - pass +class ProviderAccountFilter(ContactFilterMixin, PrimaryModelFilterMixin): + provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_id: ID | None = strawberry_django.filter_field() + account: FilterLookup[str] | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ProviderNetwork, lookups=True) -@autotype_decorator(filtersets.ProviderNetworkFilterSet) -class ProviderNetworkFilter(BaseFilterMixin): - pass +class ProviderNetworkFilter(PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_id: ID | None = strawberry_django.filter_field() + service_id: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.VirtualCircuitType, lookups=True) -@autotype_decorator(filtersets.VirtualCircuitTypeFilterSet) -class VirtualCircuitTypeFilter(BaseFilterMixin): +class VirtualCircuitTypeFilter(BaseCircuitTypeFilterMixin): pass @strawberry_django.filter(models.VirtualCircuit, lookups=True) -@autotype_decorator(filtersets.VirtualCircuitFilterSet) -class VirtualCircuitFilter(BaseFilterMixin): - pass +class VirtualCircuitFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + cid: FilterLookup[str] | None = strawberry_django.filter_field() + provider_network: Annotated['ProviderNetworkFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_network_id: ID | None = strawberry_django.filter_field() + provider_account: Annotated['ProviderAccountFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + provider_account_id: ID | None = strawberry_django.filter_field() + type: Annotated['VirtualCircuitTypeFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + type_id: ID | None = strawberry_django.filter_field() + status: Annotated['CircuitStatusEnum', strawberry.lazy('circuits.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + group_assignments: Annotated['CircuitGroupAssignmentFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.VirtualCircuitTermination, lookups=True) -@autotype_decorator(filtersets.VirtualCircuitTerminationFilterSet) -class VirtualCircuitTerminationFilter(BaseFilterMixin): - pass +class VirtualCircuitTerminationFilter( + BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin +): + virtual_circuit: Annotated['VirtualCircuitFilter', strawberry.lazy('circuits.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + virtual_circuit_id: ID | None = strawberry_django.filter_field() + role: Annotated['VirtualCircuitTerminationRoleEnum', strawberry.lazy('circuits.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + interface: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + interface_id: ID | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/circuits/graphql/types.py b/netbox/circuits/graphql/types.py index 564b5ed6f93..cdd02c8919f 100644 --- a/netbox/circuits/graphql/types.py +++ b/netbox/circuits/graphql/types.py @@ -1,4 +1,4 @@ -from typing import Annotated, List, Union +from typing import Annotated, List, TYPE_CHECKING, Union import strawberry import strawberry_django @@ -10,11 +10,15 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, ObjectType, O from tenancy.graphql.types import TenantType from .filters import * +if TYPE_CHECKING: + from dcim.graphql.types import InterfaceType, LocationType, RegionType, SiteGroupType, SiteType + from ipam.graphql.types import ASNType + __all__ = ( - 'CircuitTerminationType', - 'CircuitType', 'CircuitGroupAssignmentType', 'CircuitGroupType', + 'CircuitTerminationType', + 'CircuitType', 'CircuitTypeType', 'ProviderType', 'ProviderAccountType', @@ -28,7 +32,8 @@ __all__ = ( @strawberry_django.type( models.Provider, fields='__all__', - filters=ProviderFilter + filters=ProviderFilter, + pagination=True ) class ProviderType(NetBoxObjectType, ContactsMixin): @@ -41,7 +46,8 @@ class ProviderType(NetBoxObjectType, ContactsMixin): @strawberry_django.type( models.ProviderAccount, fields='__all__', - filters=ProviderAccountFilter + filters=ProviderAccountFilter, + pagination=True ) class ProviderAccountType(NetBoxObjectType): provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')] @@ -52,7 +58,8 @@ class ProviderAccountType(NetBoxObjectType): @strawberry_django.type( models.ProviderNetwork, fields='__all__', - filters=ProviderNetworkFilter + filters=ProviderNetworkFilter, + pagination=True ) class ProviderNetworkType(NetBoxObjectType): provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')] @@ -62,8 +69,9 @@ class ProviderNetworkType(NetBoxObjectType): @strawberry_django.type( models.CircuitTermination, - exclude=('termination_type', 'termination_id', '_location', '_region', '_site', '_site_group', '_provider_network'), - filters=CircuitTerminationFilter + exclude=['termination_type', 'termination_id', '_location', '_region', '_site', '_site_group', '_provider_network'], + filters=CircuitTerminationFilter, + pagination=True ) class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, ObjectType): circuit: Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')] @@ -82,7 +90,8 @@ class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, Ob @strawberry_django.type( models.CircuitType, fields='__all__', - filters=CircuitTypeFilter + filters=CircuitTypeFilter, + pagination=True ) class CircuitTypeType(OrganizationalObjectType): color: str @@ -93,7 +102,8 @@ class CircuitTypeType(OrganizationalObjectType): @strawberry_django.type( models.Circuit, fields='__all__', - filters=CircuitFilter + filters=CircuitFilter, + pagination=True ) class CircuitType(NetBoxObjectType, ContactsMixin): provider: ProviderType @@ -109,7 +119,8 @@ class CircuitType(NetBoxObjectType, ContactsMixin): @strawberry_django.type( models.CircuitGroup, fields='__all__', - filters=CircuitGroupFilter + filters=CircuitGroupFilter, + pagination=True ) class CircuitGroupType(OrganizationalObjectType): tenant: TenantType | None @@ -117,8 +128,9 @@ class CircuitGroupType(OrganizationalObjectType): @strawberry_django.type( models.CircuitGroupAssignment, - exclude=('member_type', 'member_id'), - filters=CircuitGroupAssignmentFilter + exclude=['member_type', 'member_id'], + filters=CircuitGroupAssignmentFilter, + pagination=True ) class CircuitGroupAssignmentType(TagsMixin, BaseObjectType): group: Annotated["CircuitGroupType", strawberry.lazy('circuits.graphql.types')] @@ -134,7 +146,8 @@ class CircuitGroupAssignmentType(TagsMixin, BaseObjectType): @strawberry_django.type( models.VirtualCircuitType, fields='__all__', - filters=VirtualCircuitTypeFilter + filters=VirtualCircuitTypeFilter, + pagination=True ) class VirtualCircuitTypeType(OrganizationalObjectType): color: str @@ -145,7 +158,8 @@ class VirtualCircuitTypeType(OrganizationalObjectType): @strawberry_django.type( models.VirtualCircuitTermination, fields='__all__', - filters=VirtualCircuitTerminationFilter + filters=VirtualCircuitTerminationFilter, + pagination=True ) class VirtualCircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType): virtual_circuit: Annotated[ @@ -161,7 +175,8 @@ class VirtualCircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType): @strawberry_django.type( models.VirtualCircuit, fields='__all__', - filters=VirtualCircuitFilter + filters=VirtualCircuitFilter, + pagination=True ) class VirtualCircuitType(NetBoxObjectType): provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"]) diff --git a/netbox/circuits/migrations/0002_squashed_0029.py b/netbox/circuits/migrations/0002_squashed_0029.py index cb61d8feb6c..0062575cd67 100644 --- a/netbox/circuits/migrations/0002_squashed_0029.py +++ b/netbox/circuits/migrations/0002_squashed_0029.py @@ -5,11 +5,11 @@ import taggit.managers class Migration(migrations.Migration): dependencies = [ - ('dcim', '0001_initial'), + ('dcim', '0001_squashed'), ('contenttypes', '0002_remove_content_type_name'), - ('circuits', '0001_initial'), - ('extras', '0001_initial'), - ('tenancy', '0001_initial'), + ('circuits', '0001_squashed'), + ('extras', '0001_squashed'), + ('tenancy', '0001_squashed_0012'), ] replaces = [ diff --git a/netbox/circuits/migrations/0038_squashed_0042.py b/netbox/circuits/migrations/0038_squashed_0042.py index fa944b76338..be07638b4ca 100644 --- a/netbox/circuits/migrations/0038_squashed_0042.py +++ b/netbox/circuits/migrations/0038_squashed_0042.py @@ -15,8 +15,8 @@ class Migration(migrations.Migration): ] dependencies = [ - ('circuits', '0037_new_cabling_models'), - ('dcim', '0160_populate_cable_ends'), + ('circuits', '0003_squashed_0037'), + ('dcim', '0160_squashed_0166'), ] operations = [ diff --git a/netbox/circuits/migrations/0043_circuittype_color.py b/netbox/circuits/migrations/0043_circuittype_color.py index 6c4dffeb660..400c419eff4 100644 --- a/netbox/circuits/migrations/0043_circuittype_color.py +++ b/netbox/circuits/migrations/0043_circuittype_color.py @@ -6,7 +6,7 @@ import utilities.fields class Migration(migrations.Migration): dependencies = [ - ('circuits', '0042_provideraccount'), + ('circuits', '0038_squashed_0042'), ] operations = [ diff --git a/netbox/circuits/migrations/0047_circuittermination__termination.py b/netbox/circuits/migrations/0047_circuittermination__termination.py index f78e17ec301..4caa3a37d3d 100644 --- a/netbox/circuits/migrations/0047_circuittermination__termination.py +++ b/netbox/circuits/migrations/0047_circuittermination__termination.py @@ -39,9 +39,6 @@ class Migration(migrations.Migration): name='termination_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q( - ('model__in', ('region', 'sitegroup', 'site', 'location', 'providernetwork')) - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', diff --git a/netbox/circuits/migrations/0051_virtualcircuit_group_assignment.py b/netbox/circuits/migrations/0051_virtualcircuit_group_assignment.py index f8c0fd653f0..0418c26e52f 100644 --- a/netbox/circuits/migrations/0051_virtualcircuit_group_assignment.py +++ b/netbox/circuits/migrations/0051_virtualcircuit_group_assignment.py @@ -51,7 +51,6 @@ class Migration(migrations.Migration): name='member_type', field=models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, - limit_choices_to=models.Q(('app_label', 'circuits'), ('model__in', ['circuit', 'virtualcircuit'])), related_name='+', to='contenttypes.contenttype', blank=True, @@ -68,7 +67,6 @@ class Migration(migrations.Migration): model_name='circuitgroupassignment', name='member_type', field=models.ForeignKey( - limit_choices_to=models.Q(('app_label', 'circuits'), ('model__in', ['circuit', 'virtualcircuit'])), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype' diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 9c7714153f0..102377296c4 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -182,7 +182,6 @@ class CircuitGroupAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, """ member_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=CIRCUIT_GROUP_ASSIGNMENT_MEMBER_MODELS, on_delete=models.PROTECT, related_name='+' ) @@ -249,7 +248,6 @@ class CircuitTermination( termination_type = models.ForeignKey( to='contenttypes.ContentType', on_delete=models.PROTECT, - limit_choices_to=Q(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES), related_name='+', blank=True, null=True diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 3bd81c33a37..644251c3517 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _ from dcim.views import PathTraceView from netbox.views import generic -from tenancy.views import ObjectContactsView from utilities.forms import ConfirmationForm from utilities.query import count_related from utilities.views import GetRelatedModelsMixin, register_model_view @@ -74,11 +73,6 @@ class ProviderBulkDeleteView(generic.BulkDeleteView): table = tables.ProviderTable -@register_model_view(Provider, 'contacts') -class ProviderContactsView(ObjectContactsView): - queryset = Provider.objects.all() - - # # ProviderAccounts # @@ -141,11 +135,6 @@ class ProviderAccountBulkDeleteView(generic.BulkDeleteView): table = tables.ProviderAccountTable -@register_model_view(ProviderAccount, 'contacts') -class ProviderAccountContactsView(ObjectContactsView): - queryset = ProviderAccount.objects.all() - - # # Provider networks # @@ -413,11 +402,6 @@ class CircuitSwapTerminations(generic.ObjectEditView): }) -@register_model_view(Circuit, 'contacts') -class CircuitContactsView(ObjectContactsView): - queryset = Circuit.objects.all() - - # # Circuit terminations # diff --git a/netbox/core/api/serializers_/data.py b/netbox/core/api/serializers_/data.py index 2c155ba6bc5..3f2ddb2a0e6 100644 --- a/netbox/core/api/serializers_/data.py +++ b/netbox/core/api/serializers_/data.py @@ -26,8 +26,8 @@ class DataSourceSerializer(NetBoxModelSerializer): model = DataSource fields = [ 'id', 'url', 'display_url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', - 'parameters', 'ignore_rules', 'comments', 'custom_fields', 'created', 'last_updated', 'last_synced', - 'file_count', + 'sync_interval', 'parameters', 'ignore_rules', 'comments', 'custom_fields', 'created', 'last_updated', + 'last_synced', 'file_count', ] brief_fields = ('id', 'url', 'display', 'name', 'description') diff --git a/netbox/core/apps.py b/netbox/core/apps.py index b1337c7ed39..f74a01aa9e9 100644 --- a/netbox/core/apps.py +++ b/netbox/core/apps.py @@ -19,6 +19,7 @@ class CoreConfig(AppConfig): def ready(self): from core.api import schema # noqa: F401 + from core.checks import check_duplicate_indexes # noqa: F401 from netbox.models.features import register_models from . import data_backends, events, search # noqa: F401 from netbox import context_managers # noqa: F401 diff --git a/netbox/core/checks.py b/netbox/core/checks.py new file mode 100644 index 00000000000..cab52a0255e --- /dev/null +++ b/netbox/core/checks.py @@ -0,0 +1,41 @@ +from django.core.checks import Error, register, Tags +from django.db.models import Index, UniqueConstraint +from django.apps import apps + +__all__ = ( + 'check_duplicate_indexes', +) + + +@register(Tags.models) +def check_duplicate_indexes(app_configs, **kwargs): + """ + Check for an index which is redundant to a declared unique constraint. + """ + errors = [] + + for model in apps.get_models(): + if not (meta := getattr(model, "_meta", None)): + continue + + index_fields = { + tuple(index.fields) for index in getattr(meta, 'indexes', []) + if isinstance(index, Index) + } + constraint_fields = { + tuple(constraint.fields) for constraint in getattr(meta, 'constraints', []) + if isinstance(constraint, UniqueConstraint) + } + + # Find overlapping definitions + if duplicated := index_fields & constraint_fields: + for fields in duplicated: + errors.append( + Error( + f"Model '{model.__name__}' defines the same field set {fields} in both `Meta.indexes` and " + f"`Meta.constraints`.", + obj=model, + ) + ) + + return errors diff --git a/netbox/core/data_backends.py b/netbox/core/data_backends.py index 770a3b25879..9ba1d5dfddd 100644 --- a/netbox/core/data_backends.py +++ b/netbox/core/data_backends.py @@ -7,13 +7,13 @@ from pathlib import Path from urllib.parse import urlparse from django import forms -from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.utils.translation import gettext as _ from netbox.data_backends import DataBackend from netbox.utils import register_data_backend from utilities.constants import HTTP_PROXY_SUPPORTED_SCHEMAS, HTTP_PROXY_SUPPORTED_SOCK_SCHEMAS +from utilities.proxy import resolve_proxies from utilities.socks import ProxyPoolManager from .exceptions import SyncError @@ -70,18 +70,18 @@ class GitBackend(DataBackend): # Initialize backend config config = ConfigDict() - self.use_socks = False + self.socks_proxy = None # Apply HTTP proxy (if configured) - if settings.HTTP_PROXIES: - if proxy := settings.HTTP_PROXIES.get(self.url_scheme, None): - if urlparse(proxy).scheme not in HTTP_PROXY_SUPPORTED_SCHEMAS: - raise ImproperlyConfigured(f"Unsupported Git DataSource proxy scheme: {urlparse(proxy).scheme}") + proxies = resolve_proxies(url=self.url, context={'client': self}) or {} + if proxy := proxies.get(self.url_scheme): + if urlparse(proxy).scheme not in HTTP_PROXY_SUPPORTED_SCHEMAS: + raise ImproperlyConfigured(f"Unsupported Git DataSource proxy scheme: {urlparse(proxy).scheme}") - if self.url_scheme in ('http', 'https'): - config.set("http", "proxy", proxy) - if urlparse(proxy).scheme in HTTP_PROXY_SUPPORTED_SOCK_SCHEMAS: - self.use_socks = True + if self.url_scheme in ('http', 'https'): + config.set("http", "proxy", proxy) + if urlparse(proxy).scheme in HTTP_PROXY_SUPPORTED_SOCK_SCHEMAS: + self.socks_proxy = proxy return config @@ -98,8 +98,8 @@ class GitBackend(DataBackend): } # check if using socks for proxy - if so need to use custom pool_manager - if self.use_socks: - clone_args['pool_manager'] = ProxyPoolManager(settings.HTTP_PROXIES.get(self.url_scheme)) + if self.socks_proxy: + clone_args['pool_manager'] = ProxyPoolManager(self.socks_proxy) if self.url_scheme in ('http', 'https'): if self.params.get('username'): @@ -147,7 +147,7 @@ class S3Backend(DataBackend): # Initialize backend config return Boto3Config( - proxies=settings.HTTP_PROXIES, + proxies=resolve_proxies(url=self.url, context={'client': self}), ) @contextmanager diff --git a/netbox/core/exceptions.py b/netbox/core/exceptions.py index 8412b0378df..5790704c21c 100644 --- a/netbox/core/exceptions.py +++ b/netbox/core/exceptions.py @@ -1,2 +1,9 @@ +from django.core.exceptions import ImproperlyConfigured + + class SyncError(Exception): pass + + +class IncompatiblePluginError(ImproperlyConfigured): + pass diff --git a/netbox/core/filtersets.py b/netbox/core/filtersets.py index 21fdaa4abe2..42ec2235058 100644 --- a/netbox/core/filtersets.py +++ b/netbox/core/filtersets.py @@ -29,6 +29,10 @@ class DataSourceFilterSet(NetBoxModelFilterSet): choices=DataSourceStatusChoices, null_value=None ) + sync_interval = django_filters.MultipleChoiceFilter( + choices=JobIntervalChoices, + null_value=None + ) class Meta: model = DataSource diff --git a/netbox/core/forms/bulk_edit.py b/netbox/core/forms/bulk_edit.py index c1f1fca4dc8..73618826d88 100644 --- a/netbox/core/forms/bulk_edit.py +++ b/netbox/core/forms/bulk_edit.py @@ -1,6 +1,7 @@ from django import forms from django.utils.translation import gettext_lazy as _ +from core.choices import JobIntervalChoices from core.models import * from netbox.forms import NetBoxModelBulkEditForm from netbox.utils import get_data_backend_choices @@ -29,6 +30,11 @@ class DataSourceBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + sync_interval = forms.ChoiceField( + choices=JobIntervalChoices, + required=False, + label=_('Sync interval') + ) comments = CommentField() parameters = forms.JSONField( label=_('Parameters'), @@ -42,8 +48,8 @@ class DataSourceBulkEditForm(NetBoxModelBulkEditForm): model = DataSource fieldsets = ( - FieldSet('type', 'enabled', 'description', 'comments', 'parameters', 'ignore_rules'), + FieldSet('type', 'enabled', 'description', 'sync_interval', 'parameters', 'ignore_rules', 'comments'), ) nullable_fields = ( - 'description', 'description', 'parameters', 'comments', 'parameters', 'ignore_rules', + 'description', 'description', 'sync_interval', 'parameters', 'parameters', 'ignore_rules' 'comments', ) diff --git a/netbox/core/forms/bulk_import.py b/netbox/core/forms/bulk_import.py index 78a859dcb39..a5791c94514 100644 --- a/netbox/core/forms/bulk_import.py +++ b/netbox/core/forms/bulk_import.py @@ -11,5 +11,6 @@ class DataSourceImportForm(NetBoxModelImportForm): class Meta: model = DataSource fields = ( - 'name', 'type', 'source_url', 'enabled', 'description', 'comments', 'parameters', 'ignore_rules', + 'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'parameters', 'ignore_rules', + 'comments', ) diff --git a/netbox/core/forms/filtersets.py b/netbox/core/forms/filtersets.py index ab4b869b739..4e72867373d 100644 --- a/netbox/core/forms/filtersets.py +++ b/netbox/core/forms/filtersets.py @@ -27,7 +27,7 @@ class DataSourceFilterForm(NetBoxModelFilterSetForm): model = DataSource fieldsets = ( FieldSet('q', 'filter_id'), - FieldSet('type', 'status', name=_('Data Source')), + FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -46,6 +46,11 @@ class DataSourceFilterForm(NetBoxModelFilterSetForm): choices=BOOLEAN_WITH_BLANK_CHOICES ) ) + sync_interval = forms.ChoiceField( + label=_('Sync interval'), + choices=JobIntervalChoices, + required=False + ) class DataFileFilterForm(NetBoxModelFilterSetForm): diff --git a/netbox/core/forms/model_forms.py b/netbox/core/forms/model_forms.py index a05377597db..0a683a381e3 100644 --- a/netbox/core/forms/model_forms.py +++ b/netbox/core/forms/model_forms.py @@ -36,7 +36,7 @@ class DataSourceForm(NetBoxModelForm): class Meta: model = DataSource fields = [ - 'name', 'type', 'source_url', 'enabled', 'description', 'comments', 'ignore_rules', 'tags', + 'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'ignore_rules', 'comments', 'tags', ] widgets = { 'ignore_rules': forms.Textarea( @@ -51,7 +51,10 @@ class DataSourceForm(NetBoxModelForm): @property def fieldsets(self): fieldsets = [ - FieldSet('name', 'type', 'source_url', 'enabled', 'description', 'tags', 'ignore_rules', name=_('Source')), + FieldSet( + 'name', 'type', 'source_url', 'description', 'tags', 'ignore_rules', name=_('Source') + ), + FieldSet('enabled', 'sync_interval', name=_('Sync')), ] if self.backend_fields: fieldsets.append( diff --git a/netbox/core/graphql/filter_mixins.py b/netbox/core/graphql/filter_mixins.py new file mode 100644 index 00000000000..670ec2ebb3c --- /dev/null +++ b/netbox/core/graphql/filter_mixins.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Annotated, TYPE_CHECKING + +import strawberry +import strawberry_django +from strawberry import ID +from strawberry_django import DatetimeFilterLookup + +if TYPE_CHECKING: + from .filters import * + +__all__ = ( + 'BaseFilterMixin', + 'BaseObjectTypeFilterMixin', + 'ChangeLogFilterMixin', +) + + +# @strawberry.input +class BaseFilterMixin: ... + + +@dataclass +class BaseObjectTypeFilterMixin(BaseFilterMixin): + id: ID | None = strawberry.UNSET + + +@dataclass +class ChangeLogFilterMixin(BaseFilterMixin): + id: ID | None = strawberry.UNSET + changelog: Annotated['ObjectChangeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + last_updated: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() diff --git a/netbox/core/graphql/filters.py b/netbox/core/graphql/filters.py index 82da685a590..e5d44674aad 100644 --- a/netbox/core/graphql/filters.py +++ b/netbox/core/graphql/filters.py @@ -1,28 +1,89 @@ -import strawberry_django +from datetime import datetime +from typing import Annotated, TYPE_CHECKING -from core import filtersets, models -from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin +import strawberry +import strawberry_django +from django.contrib.contenttypes.models import ContentType as DjangoContentType +from strawberry.scalars import ID +from strawberry_django import DatetimeFilterLookup, FilterLookup + +from core import models +from core.graphql.filter_mixins import BaseFilterMixin +from netbox.graphql.filter_mixins import PrimaryModelFilterMixin + +if TYPE_CHECKING: + from netbox.graphql.filter_lookups import IntegerLookup, JSONFilter + from users.graphql.filters import UserFilter __all__ = ( 'DataFileFilter', 'DataSourceFilter', 'ObjectChangeFilter', + 'ContentTypeFilter', ) @strawberry_django.filter(models.DataFile, lookups=True) -@autotype_decorator(filtersets.DataFileFilterSet) class DataFileFilter(BaseFilterMixin): - pass + id: ID | None = strawberry_django.filter_field() + created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + last_updated: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + source: Annotated['DataSourceFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + source_id: ID | None = strawberry_django.filter_field() + path: FilterLookup[str] | None = strawberry_django.filter_field() + size: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + hash: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.DataSource, lookups=True) -@autotype_decorator(filtersets.DataSourceFilterSet) -class DataSourceFilter(BaseFilterMixin): - pass +class DataSourceFilter(PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + type: FilterLookup[str] | None = strawberry_django.filter_field() + source_url: FilterLookup[str] | None = strawberry_django.filter_field() + status: FilterLookup[str] | None = strawberry_django.filter_field() + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + ignore_rules: FilterLookup[str] | None = strawberry_django.filter_field() + parameters: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + last_synced: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + datafiles: Annotated['DataFileFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ObjectChange, lookups=True) -@autotype_decorator(filtersets.ObjectChangeFilterSet) class ObjectChangeFilter(BaseFilterMixin): - pass + id: ID | None = strawberry_django.filter_field() + time: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + user_name: FilterLookup[str] | None = strawberry_django.filter_field() + request_id: FilterLookup[str] | None = strawberry_django.filter_field() + action: FilterLookup[str] | None = strawberry_django.filter_field() + changed_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + changed_object_type_id: ID | None = strawberry_django.filter_field() + changed_object_id: ID | None = strawberry_django.filter_field() + related_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + related_object_id: ID | None = strawberry_django.filter_field() + object_repr: FilterLookup[str] | None = strawberry_django.filter_field() + prechange_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + postchange_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + + +@strawberry_django.filter(DjangoContentType, lookups=True) +class ContentTypeFilter(BaseFilterMixin): + id: ID | None = strawberry_django.filter_field() + app_label: FilterLookup[str] | None = strawberry_django.filter_field() + model: FilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/core/graphql/mixins.py b/netbox/core/graphql/mixins.py index 5195b52a0d8..72191e6fd64 100644 --- a/netbox/core/graphql/mixins.py +++ b/netbox/core/graphql/mixins.py @@ -1,4 +1,4 @@ -from typing import Annotated, List +from typing import Annotated, List, TYPE_CHECKING import strawberry import strawberry_django @@ -6,6 +6,9 @@ from django.contrib.contenttypes.models import ContentType from core.models import ObjectChange +if TYPE_CHECKING: + from netbox.core.graphql.types import ObjectChangeType + __all__ = ( 'ChangelogMixin', ) diff --git a/netbox/core/graphql/types.py b/netbox/core/graphql/types.py index 09385d7c124..ffaa244116d 100644 --- a/netbox/core/graphql/types.py +++ b/netbox/core/graphql/types.py @@ -2,12 +2,14 @@ from typing import Annotated, List import strawberry import strawberry_django +from django.contrib.contenttypes.models import ContentType as DjangoContentType from core import models from netbox.graphql.types import BaseObjectType, NetBoxObjectType from .filters import * __all__ = ( + 'ContentType', 'DataFileType', 'DataSourceType', 'ObjectChangeType', @@ -17,7 +19,8 @@ __all__ = ( @strawberry_django.type( models.DataFile, exclude=['data',], - filters=DataFileFilter + filters=DataFileFilter, + pagination=True ) class DataFileType(BaseObjectType): source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] @@ -26,7 +29,8 @@ class DataFileType(BaseObjectType): @strawberry_django.type( models.DataSource, fields='__all__', - filters=DataSourceFilter + filters=DataSourceFilter, + pagination=True ) class DataSourceType(NetBoxObjectType): @@ -36,7 +40,17 @@ class DataSourceType(NetBoxObjectType): @strawberry_django.type( models.ObjectChange, fields='__all__', - filters=ObjectChangeFilter + filters=ObjectChangeFilter, + pagination=True ) class ObjectChangeType(BaseObjectType): pass + + +@strawberry_django.type( + DjangoContentType, + fields='__all__', + pagination=True +) +class ContentType: + pass diff --git a/netbox/core/jobs.py b/netbox/core/jobs.py index 891b1cbdb31..b3dfaf1e766 100644 --- a/netbox/core/jobs.py +++ b/netbox/core/jobs.py @@ -5,6 +5,7 @@ import sys from django.conf import settings from netbox.jobs import JobRunner, system_job from netbox.search.backends import search_backend +from utilities.proxy import resolve_proxies from .choices import DataSourceStatusChoices, JobIntervalChoices from .exceptions import SyncError from .models import DataSource @@ -71,7 +72,7 @@ class SystemHousekeepingJob(JobRunner): url=settings.CENSUS_URL, params=census_data, timeout=3, - proxies=settings.HTTP_PROXIES + proxies=resolve_proxies(url=settings.CENSUS_URL) ) except requests.exceptions.RequestException: pass diff --git a/netbox/core/migrations/0006_datasource_type_remove_choices.py b/netbox/core/migrations/0006_datasource_type_remove_choices.py index 7c9914298f4..6a7fe252173 100644 --- a/netbox/core/migrations/0006_datasource_type_remove_choices.py +++ b/netbox/core/migrations/0006_datasource_type_remove_choices.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('core', '0005_job_created_auto_now'), + ('core', '0001_squashed_0005'), ] operations = [ diff --git a/netbox/core/migrations/0013_datasource_sync_interval.py b/netbox/core/migrations/0013_datasource_sync_interval.py new file mode 100644 index 00000000000..ec3d2a5d6e6 --- /dev/null +++ b/netbox/core/migrations/0013_datasource_sync_interval.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.6 on 2025-02-26 19:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0012_job_object_type_optional'), + ] + + operations = [ + migrations.AddField( + model_name='datasource', + name='sync_interval', + field=models.PositiveSmallIntegerField(blank=True, null=True), + ), + ] diff --git a/netbox/core/migrations/0014_remove_redundant_indexes.py b/netbox/core/migrations/0014_remove_redundant_indexes.py new file mode 100644 index 00000000000..fc90a67fa7e --- /dev/null +++ b/netbox/core/migrations/0014_remove_redundant_indexes.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2b1 on 2025-04-03 18:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0013_datasource_sync_interval'), + ] + + operations = [ + migrations.RemoveIndex( + model_name='autosyncrecord', + name='core_autosy_object__c17bac_idx', + ), + migrations.RemoveIndex( + model_name='datafile', + name='core_datafile_source_path', + ), + migrations.RemoveIndex( + model_name='managedfile', + name='core_managedfile_root_path', + ), + ] diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 39ee8fa575f..52a11c58ee3 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -59,6 +59,12 @@ class DataSource(JobsMixin, PrimaryModel): verbose_name=_('enabled'), default=True ) + sync_interval = models.PositiveSmallIntegerField( + verbose_name=_('sync interval'), + choices=JobIntervalChoices, + blank=True, + null=True + ) ignore_rules = models.TextField( verbose_name=_('ignore rules'), blank=True, @@ -304,9 +310,6 @@ class DataFile(models.Model): name='%(app_label)s_%(class)s_unique_source_path' ), ) - indexes = [ - models.Index(fields=('source', 'path'), name='core_datafile_source_path'), - ] verbose_name = _('data file') verbose_name_plural = _('data files') @@ -351,17 +354,6 @@ class DataFile(models.Model): return is_modified - def write_to_disk(self, path, overwrite=False): - """ - Write the object's data to disk at the specified path - """ - # Check whether file already exists - if os.path.isfile(path) and not overwrite: - raise FileExistsError() - - with open(path, 'wb+') as new_file: - new_file.write(self.data) - class AutoSyncRecord(models.Model): """ @@ -392,8 +384,5 @@ class AutoSyncRecord(models.Model): name='%(app_label)s_%(class)s_object' ), ) - indexes = ( - models.Index(fields=('object_type', 'object_id')), - ) verbose_name = _('auto sync record') verbose_name_plural = _('auto sync records') diff --git a/netbox/core/models/files.py b/netbox/core/models/files.py index cc446bac7c8..d60269b8b26 100644 --- a/netbox/core/models/files.py +++ b/netbox/core/models/files.py @@ -1,13 +1,16 @@ import logging import os +from functools import cached_property from django.conf import settings from django.core.exceptions import ValidationError from django.db import models +from django.core.files.storage import storages from django.urls import reverse from django.utils.translation import gettext as _ from ..choices import ManagedFileRootPathChoices +from extras.storage import ScriptFileSystemStorage from netbox.models.features import SyncedDataMixin from utilities.querysets import RestrictedQuerySet @@ -55,9 +58,6 @@ class ManagedFile(SyncedDataMixin, models.Model): name='%(app_label)s_%(class)s_unique_root_path' ), ) - indexes = [ - models.Index(fields=('file_root', 'file_path'), name='core_managedfile_root_path'), - ] verbose_name = _('managed file') verbose_name_plural = _('managed files') @@ -76,15 +76,35 @@ class ManagedFile(SyncedDataMixin, models.Model): return os.path.join(self._resolve_root_path(), self.file_path) def _resolve_root_path(self): - return { - 'scripts': settings.SCRIPTS_ROOT, - 'reports': settings.REPORTS_ROOT, - }[self.file_root] + storage = self.storage + if isinstance(storage, ScriptFileSystemStorage): + return { + 'scripts': settings.SCRIPTS_ROOT, + 'reports': settings.REPORTS_ROOT, + }[self.file_root] + else: + return "" def sync_data(self): if self.data_file: self.file_path = os.path.basename(self.data_path) - self.data_file.write_to_disk(self.full_path, overwrite=True) + self._write_to_disk(self.full_path, overwrite=True) + + def _write_to_disk(self, path, overwrite=False): + """ + Write the object's data to disk at the specified path + """ + # Check whether file already exists + storage = self.storage + if storage.exists(path) and not overwrite: + raise FileExistsError() + + with storage.open(path, 'wb+') as new_file: + new_file.write(self.data) + + @cached_property + def storage(self): + return storages.create_storage(storages.backends["scripts"]) def clean(self): super().clean() @@ -104,8 +124,9 @@ class ManagedFile(SyncedDataMixin, models.Model): def delete(self, *args, **kwargs): # Delete file from disk + storage = self.storage try: - os.remove(self.full_path) + storage.delete(self.full_path) except FileNotFoundError: pass diff --git a/netbox/core/plugins.py b/netbox/core/plugins.py index e6d09711f6b..42930bbc87c 100644 --- a/netbox/core/plugins.py +++ b/netbox/core/plugins.py @@ -11,6 +11,7 @@ from django.core.cache import cache from netbox.plugins import PluginConfig from netbox.registry import registry from utilities.datetime import datetime_from_timestamp +from utilities.proxy import resolve_proxies USER_AGENT_STRING = f'NetBox/{settings.RELEASE.version} {settings.RELEASE.edition}' CACHE_KEY_CATALOG_FEED = 'plugins-catalog-feed' @@ -64,9 +65,11 @@ class Plugin: is_certified: bool = False release_latest: PluginVersion = field(default_factory=PluginVersion) release_recent_history: list[PluginVersion] = field(default_factory=list) - is_local: bool = False # extra field for locally installed plugins - is_installed: bool = False + is_local: bool = False # Indicates that the plugin is listed in settings.PLUGINS (i.e. installed) + is_loaded: bool = False # Indicates whether the plugin successfully loaded at launch installed_version: str = '' + netbox_min_version: str = '' + netbox_max_version: str = '' def get_local_plugins(plugins=None): @@ -77,7 +80,7 @@ def get_local_plugins(plugins=None): local_plugins = {} # Gather all locally-installed plugins - for plugin_name in registry['plugins']['installed']: + for plugin_name in settings.PLUGINS: plugin = importlib.import_module(plugin_name) plugin_config: PluginConfig = plugin.config installed_version = plugin_config.version @@ -91,19 +94,28 @@ def get_local_plugins(plugins=None): tag_line=plugin_config.description, description_short=plugin_config.description, is_local=True, - is_installed=True, + is_loaded=plugin_name in registry['plugins']['installed'], installed_version=installed_version, + netbox_min_version=plugin_config.min_version, + netbox_max_version=plugin_config.max_version, ) # Update catalog entries for local plugins, or add them to the list if not listed for k, v in local_plugins.items(): if k in plugins: - plugins[k].is_local = True - plugins[k].is_installed = True + plugins[k].is_local = v.is_local + plugins[k].is_loaded = v.is_loaded plugins[k].installed_version = v.installed_version else: plugins[k] = v + # Update plugin table config for hidden and static plugins + hidden = settings.PLUGINS_CATALOG_CONFIG.get('hidden', []) + static = settings.PLUGINS_CATALOG_CONFIG.get('static', []) + for k, v in plugins.items(): + v.hidden = k in hidden + v.static = k in static + return plugins @@ -120,10 +132,11 @@ def get_catalog_plugins(): def get_pages(): # TODO: pagination is currently broken in API payload = {'page': '1', 'per_page': '50'} + proxies = resolve_proxies(url=settings.PLUGIN_CATALOG_URL) first_page = session.get( settings.PLUGIN_CATALOG_URL, headers={'User-Agent': USER_AGENT_STRING}, - proxies=settings.HTTP_PROXIES, + proxies=proxies, timeout=3, params=payload ).json() @@ -135,7 +148,7 @@ def get_catalog_plugins(): next_page = session.get( settings.PLUGIN_CATALOG_URL, headers={'User-Agent': USER_AGENT_STRING}, - proxies=settings.HTTP_PROXIES, + proxies=proxies, timeout=3, params=payload ).json() diff --git a/netbox/core/signals.py b/netbox/core/signals.py index 06432bf4ce4..bdaa60f9719 100644 --- a/netbox/core/signals.py +++ b/netbox/core/signals.py @@ -8,16 +8,15 @@ from django.dispatch import receiver, Signal from django.utils.translation import gettext_lazy as _ from django_prometheus.models import model_deletes, model_inserts, model_updates -from core.choices import ObjectChangeActionChoices +from core.choices import JobStatusChoices, ObjectChangeActionChoices from core.events import * -from core.models import ObjectChange from extras.events import enqueue_event from extras.utils import run_validators from netbox.config import get_config from netbox.context import current_request, events_queue from netbox.models.features import ChangeLoggingMixin from utilities.exceptions import AbortRequest -from .models import ConfigRevision +from .models import ConfigRevision, DataSource, ObjectChange __all__ = ( 'clear_events', @@ -182,6 +181,25 @@ def clear_events_queue(sender, **kwargs): # DataSource handlers # +@receiver(post_save, sender=DataSource) +def enqueue_sync_job(instance, created, **kwargs): + """ + When a DataSource is saved, check its sync_interval and enqueue a sync job if appropriate. + """ + from .jobs import SyncDataSourceJob + + if instance.enabled and instance.sync_interval: + SyncDataSourceJob.enqueue_once(instance, interval=instance.sync_interval) + elif not created: + # Delete any previously scheduled recurring jobs for this DataSource + for job in SyncDataSourceJob.get_jobs(instance).defer('data').filter( + interval__isnull=False, + status=JobStatusChoices.STATUS_SCHEDULED + ): + # Call delete() per instance to ensure the associated background task is deleted as well + job.delete() + + @receiver(post_sync) def auto_sync(instance, **kwargs): """ diff --git a/netbox/core/tables/data.py b/netbox/core/tables/data.py index 4059ea9bc4d..5d237c689cf 100644 --- a/netbox/core/tables/data.py +++ b/netbox/core/tables/data.py @@ -25,6 +25,9 @@ class DataSourceTable(NetBoxTable): enabled = columns.BooleanColumn( verbose_name=_('Enabled'), ) + sync_interval = columns.ChoiceFieldColumn( + verbose_name=_('Sync interval'), + ) tags = columns.TagColumn( url_name='core:datasource_list' ) @@ -35,10 +38,10 @@ class DataSourceTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = DataSource fields = ( - 'pk', 'id', 'name', 'type', 'status', 'enabled', 'source_url', 'description', 'comments', 'parameters', - 'created', 'last_updated', 'file_count', + 'pk', 'id', 'name', 'type', 'status', 'enabled', 'source_url', 'description', 'sync_interval', 'comments', + 'parameters', 'created', 'last_updated', 'file_count', ) - default_columns = ('pk', 'name', 'type', 'status', 'enabled', 'description', 'file_count') + default_columns = ('pk', 'name', 'type', 'status', 'enabled', 'description', 'sync_interval', 'file_count') class DataFileTable(NetBoxTable): diff --git a/netbox/core/tables/plugins.py b/netbox/core/tables/plugins.py index 96c612366d6..20bd0eee634 100644 --- a/netbox/core/tables/plugins.py +++ b/netbox/core/tables/plugins.py @@ -1,7 +1,10 @@ import django_tables2 as tables +from django.urls import reverse +from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from netbox.tables import BaseTable, columns +from .template_code import PLUGIN_IS_INSTALLED __all__ = ( 'CatalogPluginTable', @@ -40,20 +43,22 @@ class PluginVersionTable(BaseTable): class CatalogPluginTable(BaseTable): title_long = tables.Column( - linkify=('core:plugin', [tables.A('config_name')]), - verbose_name=_('Name') + verbose_name=_('Name'), ) author = tables.Column( accessor=tables.A('author__name'), verbose_name=_('Author') ) is_local = columns.BooleanColumn( + false_mark=None, verbose_name=_('Local') ) - is_installed = columns.BooleanColumn( - verbose_name=_('Installed') + is_installed = columns.TemplateColumn( + verbose_name=_('Active'), + template_code=PLUGIN_IS_INSTALLED ) is_certified = columns.BooleanColumn( + false_mark=None, verbose_name=_('Certified') ) created_at = columns.DateTimeColumn( @@ -82,3 +87,9 @@ class CatalogPluginTable(BaseTable): # List installed plugins first, then certified plugins, then # everything else (with each tranche ordered alphabetically) order_by = ('-is_installed', '-is_certified', 'name') + + def render_title_long(self, value, record): + if record.static: + return value + url = reverse('core:plugin', args=[record.config_name]) + return mark_safe(f"{value}") diff --git a/netbox/core/tables/template_code.py b/netbox/core/tables/template_code.py index c8f0058e71d..9fc652c4c58 100644 --- a/netbox/core/tables/template_code.py +++ b/netbox/core/tables/template_code.py @@ -14,3 +14,15 @@ OBJECTCHANGE_OBJECT = """ OBJECTCHANGE_REQUEST_ID = """ {{ value }} """ + +PLUGIN_IS_INSTALLED = """ +{% if record.is_local %} + {% if record.is_loaded %} + + {% else %} + + {% endif %} +{% else %} + +{% endif %} +""" diff --git a/netbox/core/tests/test_filtersets.py b/netbox/core/tests/test_filtersets.py index 310be1d0efc..b7dfd516e24 100644 --- a/netbox/core/tests/test_filtersets.py +++ b/netbox/core/tests/test_filtersets.py @@ -27,7 +27,8 @@ class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests): source_url='file:///var/tmp/source1/', status=DataSourceStatusChoices.NEW, enabled=True, - description='foobar1' + description='foobar1', + sync_interval=JobIntervalChoices.INTERVAL_HOURLY ), DataSource( name='Data Source 2', @@ -35,14 +36,16 @@ class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests): source_url='file:///var/tmp/source2/', status=DataSourceStatusChoices.SYNCING, enabled=True, - description='foobar2' + description='foobar2', + sync_interval=JobIntervalChoices.INTERVAL_DAILY ), DataSource( name='Data Source 3', type='git', source_url='https://example.com/git/source3', status=DataSourceStatusChoices.COMPLETED, - enabled=False + enabled=False, + sync_interval=JobIntervalChoices.INTERVAL_WEEKLY ), ) DataSource.objects.bulk_create(data_sources) @@ -73,6 +76,10 @@ class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'status': [DataSourceStatusChoices.NEW, DataSourceStatusChoices.SYNCING]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_sync_interval(self): + params = {'sync_interval': [JobIntervalChoices.INTERVAL_HOURLY, JobIntervalChoices.INTERVAL_DAILY]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + class DataFileTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = DataFile.objects.all() diff --git a/netbox/core/views.py b/netbox/core/views.py index 1f8bff9236c..c63aa3f8108 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -613,6 +613,8 @@ class PluginListView(BasePluginView): if q: plugins = [obj for obj in plugins if q.casefold() in obj.title_short.casefold()] + plugins = [plugin for plugin in plugins if not plugin.hidden] + table = CatalogPluginTable(plugins, user=request.user) table.configure(request) diff --git a/netbox/dcim/api/serializers_/device_components.py b/netbox/dcim/api/serializers_/device_components.py index a6767bb6f5b..8b9cd42dff4 100644 --- a/netbox/dcim/api/serializers_/device_components.py +++ b/netbox/dcim/api/serializers_/device_components.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from django.contrib.contenttypes.models import ContentType from drf_spectacular.utils import extend_schema_field from rest_framework import serializers @@ -155,10 +156,10 @@ class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, Conne class Meta: model = PowerOutlet fields = [ - 'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', - 'feed_leg', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', - 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', - 'created', 'last_updated', '_occupied', + 'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'status', 'color', + 'power_port', 'feed_leg', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', + 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', + 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', 'cable', '_occupied') @@ -232,8 +233,56 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect def validate(self, data): - # Validate many-to-many VLAN assignments if not self.nested: + + # Validate 802.1q mode and vlan(s) + mode = None + tagged_vlans = [] + + # Gather Information + if self.instance: + mode = data.get('mode') if 'mode' in data.keys() else self.instance.mode + untagged_vlan = data.get('untagged_vlan') if 'untagged_vlan' in data.keys() else \ + self.instance.untagged_vlan + qinq_svlan = data.get('qinq_svlan') if 'qinq_svlan' in data.keys() else \ + self.instance.qinq_svlan + tagged_vlans = data.get('tagged_vlans') if 'tagged_vlans' in data.keys() else \ + self.instance.tagged_vlans.all() + else: + mode = data.get('mode', None) + untagged_vlan = data.get('untagged_vlan') if 'untagged_vlan' in data.keys() else None + qinq_svlan = data.get('qinq_svlan') if 'qinq_svlan' in data.keys() else None + tagged_vlans = data.get('tagged_vlans') if 'tagged_vlans' in data.keys() else None + + errors = {} + + # Non Q-in-Q mode with service vlan set + if mode != InterfaceModeChoices.MODE_Q_IN_Q and qinq_svlan: + errors.update({ + 'qinq_svlan': _("Interface mode does not support q-in-q service vlan") + }) + # Routed mode + if not mode: + # Untagged vlan + if untagged_vlan: + errors.update({ + 'untagged_vlan': _("Interface mode does not support untagged vlan") + }) + # Tagged vlan + if tagged_vlans: + errors.update({ + 'tagged_vlans': _("Interface mode does not support tagged vlans") + }) + # Non-tagged mode + elif mode in (InterfaceModeChoices.MODE_TAGGED_ALL, InterfaceModeChoices.MODE_ACCESS) and tagged_vlans: + errors.update({ + 'tagged_vlans': _("Interface mode does not support tagged vlans") + }) + + if errors: + raise serializers.ValidationError(errors) + + # Validate many-to-many VLAN assignments device = self.instance.device if self.instance else data.get('device') for vlan in data.get('tagged_vlans', []): if vlan.site not in [device.site, None]: diff --git a/netbox/dcim/api/serializers_/devicetypes.py b/netbox/dcim/api/serializers_/devicetypes.py index 0ce2af2f89a..61e3833ec1b 100644 --- a/netbox/dcim/api/serializers_/devicetypes.py +++ b/netbox/dcim/api/serializers_/devicetypes.py @@ -4,8 +4,8 @@ from django.utils.translation import gettext as _ from rest_framework import serializers from dcim.choices import * -from dcim.models import DeviceType, ModuleType -from netbox.api.fields import ChoiceField, RelatedObjectCountField +from dcim.models import DeviceType, ModuleType, ModuleTypeProfile +from netbox.api.fields import AttributesField, ChoiceField, RelatedObjectCountField from netbox.api.serializers import NetBoxModelSerializer from netbox.choices import * from .manufacturers import ManufacturerSerializer @@ -13,6 +13,7 @@ from .platforms import PlatformSerializer __all__ = ( 'DeviceTypeSerializer', + 'ModuleTypeProfileSerializer', 'ModuleTypeSerializer', ) @@ -62,7 +63,23 @@ class DeviceTypeSerializer(NetBoxModelSerializer): brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description', 'device_count') +class ModuleTypeProfileSerializer(NetBoxModelSerializer): + + class Meta: + model = ModuleTypeProfile + fields = [ + 'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'comments', 'tags', 'custom_fields', + 'created', 'last_updated', + ] + brief_fields = ('id', 'url', 'display', 'name', 'description') + + class ModuleTypeSerializer(NetBoxModelSerializer): + profile = ModuleTypeProfileSerializer( + nested=True, + required=False, + allow_null=True + ) manufacturer = ManufacturerSerializer( nested=True ) @@ -78,12 +95,17 @@ class ModuleTypeSerializer(NetBoxModelSerializer): required=False, allow_null=True ) + attributes = AttributesField( + source='attribute_data', + required=False, + allow_null=True + ) class Meta: model = ModuleType fields = [ - 'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'part_number', 'airflow', - 'weight', 'weight_unit', 'description', 'comments', 'tags', 'custom_fields', - 'created', 'last_updated', + 'id', 'url', 'display_url', 'display', 'profile', 'manufacturer', 'model', 'part_number', 'airflow', + 'weight', 'weight_unit', 'description', 'attributes', 'comments', 'tags', 'custom_fields', 'created', + 'last_updated', ] - brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'description') + brief_fields = ('id', 'url', 'display', 'profile', 'manufacturer', 'model', 'description') diff --git a/netbox/dcim/api/serializers_/nested.py b/netbox/dcim/api/serializers_/nested.py index ea346cc63fa..0e9eaa52fe8 100644 --- a/netbox/dcim/api/serializers_/nested.py +++ b/netbox/dcim/api/serializers_/nested.py @@ -52,6 +52,13 @@ class NestedLocationSerializer(WritableNestedSerializer): fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth'] +class NestedDeviceRoleSerializer(WritableNestedSerializer): + + class Meta: + model = models.DeviceRole + fields = ['id', 'url', 'display_url', 'display', 'name'] + + class NestedDeviceSerializer(WritableNestedSerializer): class Meta: diff --git a/netbox/dcim/api/serializers_/racks.py b/netbox/dcim/api/serializers_/racks.py index 1378c265a85..4bc2900dcd4 100644 --- a/netbox/dcim/api/serializers_/racks.py +++ b/netbox/dcim/api/serializers_/racks.py @@ -70,8 +70,8 @@ class RackTypeSerializer(RackBaseSerializer): model = RackType fields = [ 'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'description', 'form_factor', - 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'weight', - 'max_weight', 'weight_unit', 'mounting_depth', 'description', 'comments', 'tags', + 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', + 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'mounting_depth', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description') @@ -129,9 +129,9 @@ class RackSerializer(RackBaseSerializer): fields = [ 'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'weight', - 'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', - 'airflow', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', - 'powerfeed_count', + 'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', + 'mounting_depth', 'airflow', 'description', 'comments', 'tags', 'custom_fields', + 'created', 'last_updated', 'device_count', 'powerfeed_count', ] brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count') diff --git a/netbox/dcim/api/serializers_/roles.py b/netbox/dcim/api/serializers_/roles.py index 8f922da1079..17eeaa949ec 100644 --- a/netbox/dcim/api/serializers_/roles.py +++ b/netbox/dcim/api/serializers_/roles.py @@ -1,7 +1,8 @@ from dcim.models import DeviceRole, InventoryItemRole from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from netbox.api.fields import RelatedObjectCountField -from netbox.api.serializers import NetBoxModelSerializer +from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer +from .nested import NestedDeviceRoleSerializer __all__ = ( 'DeviceRoleSerializer', @@ -9,7 +10,8 @@ __all__ = ( ) -class DeviceRoleSerializer(NetBoxModelSerializer): +class DeviceRoleSerializer(NestedGroupModelSerializer): + parent = NestedDeviceRoleSerializer(required=False, allow_null=True, default=None) config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None) # Related object counts @@ -19,10 +21,13 @@ class DeviceRoleSerializer(NetBoxModelSerializer): class Meta: model = DeviceRole fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', + 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'parent', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', + 'comments', '_depth', ] - brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count') + brief_fields = ( + 'id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count', '_depth' + ) class InventoryItemRoleSerializer(NetBoxModelSerializer): diff --git a/netbox/dcim/api/serializers_/sites.py b/netbox/dcim/api/serializers_/sites.py index b818cd9541f..90f7b5d359e 100644 --- a/netbox/dcim/api/serializers_/sites.py +++ b/netbox/dcim/api/serializers_/sites.py @@ -27,7 +27,7 @@ class RegionSerializer(NestedGroupModelSerializer): model = Region fields = [ 'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', - 'created', 'last_updated', 'site_count', 'prefix_count', '_depth', + 'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth', ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth') @@ -41,7 +41,7 @@ class SiteGroupSerializer(NestedGroupModelSerializer): model = SiteGroup fields = [ 'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', - 'created', 'last_updated', 'site_count', 'prefix_count', '_depth', + 'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth', ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth') @@ -93,6 +93,6 @@ class LocationSerializer(NestedGroupModelSerializer): fields = [ 'id', 'url', 'display_url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', - 'prefix_count', '_depth', + 'prefix_count', 'comments', '_depth', ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth') diff --git a/netbox/dcim/api/urls.py b/netbox/dcim/api/urls.py index fc374037457..734ac13db40 100644 --- a/netbox/dcim/api/urls.py +++ b/netbox/dcim/api/urls.py @@ -21,6 +21,7 @@ router.register('rack-reservations', views.RackReservationViewSet) router.register('manufacturers', views.ManufacturerViewSet) router.register('device-types', views.DeviceTypeViewSet) router.register('module-types', views.ModuleTypeViewSet) +router.register('module-type-profiles', views.ModuleTypeProfileViewSet) # Device type components router.register('console-port-templates', views.ConsolePortTemplateViewSet) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index d7dbbef918e..575ee770f91 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -269,6 +269,12 @@ class DeviceTypeViewSet(NetBoxModelViewSet): filterset_class = filtersets.DeviceTypeFilterSet +class ModuleTypeProfileViewSet(NetBoxModelViewSet): + queryset = ModuleTypeProfile.objects.all() + serializer_class = serializers.ModuleTypeProfileSerializer + filterset_class = filtersets.ModuleTypeProfileFilterSet + + class ModuleTypeViewSet(NetBoxModelViewSet): queryset = ModuleType.objects.all() serializer_class = serializers.ModuleTypeSerializer diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index c5b6cbcadbf..47d774bd27a 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -128,14 +128,15 @@ class RackElevationDetailRenderChoices(ChoiceSet): class RackAirflowChoices(ChoiceSet): + key = 'Rack.airflow' FRONT_TO_REAR = 'front-to-rear' REAR_TO_FRONT = 'rear-to-front' - CHOICES = ( + CHOICES = [ (FRONT_TO_REAR, _('Front to rear')), (REAR_TO_FRONT, _('Rear to front')), - ) + ] # @@ -191,6 +192,7 @@ class DeviceStatusChoices(ChoiceSet): class DeviceAirflowChoices(ChoiceSet): + key = 'Device.airflow' AIRFLOW_FRONT_TO_REAR = 'front-to-rear' AIRFLOW_REAR_TO_FRONT = 'rear-to-front' @@ -203,7 +205,7 @@ class DeviceAirflowChoices(ChoiceSet): AIRFLOW_PASSIVE = 'passive' AIRFLOW_MIXED = 'mixed' - CHOICES = ( + CHOICES = [ (AIRFLOW_FRONT_TO_REAR, _('Front to rear')), (AIRFLOW_REAR_TO_FRONT, _('Rear to front')), (AIRFLOW_LEFT_TO_RIGHT, _('Left to right')), @@ -214,7 +216,7 @@ class DeviceAirflowChoices(ChoiceSet): (AIRFLOW_TOP_TO_BOTTOM, _('Top to bottom')), (AIRFLOW_PASSIVE, _('Passive')), (AIRFLOW_MIXED, _('Mixed')), - ) + ] # @@ -242,6 +244,7 @@ class ModuleStatusChoices(ChoiceSet): class ModuleAirflowChoices(ChoiceSet): + key = 'Module.airflow' FRONT_TO_REAR = 'front-to-rear' REAR_TO_FRONT = 'rear-to-front' @@ -250,14 +253,14 @@ class ModuleAirflowChoices(ChoiceSet): SIDE_TO_REAR = 'side-to-rear' PASSIVE = 'passive' - CHOICES = ( + CHOICES = [ (FRONT_TO_REAR, _('Front to rear')), (REAR_TO_FRONT, _('Rear to front')), (LEFT_TO_RIGHT, _('Left to right')), (RIGHT_TO_LEFT, _('Right to left')), (SIDE_TO_REAR, _('Side to rear')), (PASSIVE, _('Passive')), - ) + ] # @@ -1627,6 +1630,23 @@ class PowerFeedPhaseChoices(ChoiceSet): ) +# +# PowerOutlets +# +class PowerOutletStatusChoices(ChoiceSet): + key = 'PowerOutlet.status' + + STATUS_ENABLED = 'enabled' + STATUS_DISABLED = 'disabled' + STATUS_FAULTY = 'faulty' + + CHOICES = [ + (STATUS_ENABLED, _('Enabled'), 'green'), + (STATUS_DISABLED, _('Disabled'), 'red'), + (STATUS_FAULTY, _('Faulty'), 'gray'), + ] + + # # VDC # diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 60c3c4d38bc..fed660c1f15 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -11,7 +11,8 @@ from ipam.filtersets import PrimaryIPFilterSet from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF from netbox.choices import ColorChoices from netbox.filtersets import ( - BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet, + AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet, + OrganizationalModelFilterSet, ) from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet from tenancy.models import * @@ -58,6 +59,7 @@ __all__ = ( 'ModuleBayTemplateFilterSet', 'ModuleFilterSet', 'ModuleTypeFilterSet', + 'ModuleTypeProfileFilterSet', 'PathEndpointFilterSet', 'PlatformFilterSet', 'PowerConnectionFilterSet', @@ -81,7 +83,7 @@ __all__ = ( ) -class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): +class RegionFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Region.objects.all(), label=_('Parent region (ID)'), @@ -111,7 +113,7 @@ class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): fields = ('id', 'name', 'slug', 'description') -class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): +class SiteGroupFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=SiteGroup.objects.all(), label=_('Parent site group (ID)'), @@ -205,7 +207,7 @@ class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe return queryset.filter(qs_filter).distinct() -class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalModelFilterSet): +class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, NestedGroupModelFilterSet): region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', @@ -275,13 +277,13 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalM fields = ('id', 'name', 'slug', 'facility', 'description') def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(name__icontains=value) | - Q(facility__icontains=value) | - Q(description__icontains=value) - ) + # extended in order to include querying on Location.facility + queryset = super().search(queryset, name, value) + + if value.strip(): + queryset = queryset | queryset.model.objects.filter(facility__icontains=value) + + return queryset class RackRoleFilterSet(OrganizationalModelFilterSet): @@ -312,8 +314,8 @@ class RackTypeFilterSet(NetBoxModelFilterSet): class Meta: model = RackType fields = ( - 'id', 'model', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', - 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', + 'id', 'model', 'slug', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', + 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', ) def search(self, queryset, name, value): @@ -425,8 +427,8 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe model = Rack fields = ( 'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'starting_unit', 'desc_units', 'outer_width', - 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', - 'description', + 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', + 'weight_unit', 'description', ) def search(self, queryset, name, value): @@ -673,7 +675,33 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet): return queryset.exclude(inventoryitemtemplates__isnull=value) -class ModuleTypeFilterSet(NetBoxModelFilterSet): +class ModuleTypeProfileFilterSet(NetBoxModelFilterSet): + + class Meta: + model = ModuleTypeProfile + fields = ('id', 'name', 'description') + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(name__icontains=value) | + Q(description__icontains=value) | + Q(comments__icontains=value) + ) + + +class ModuleTypeFilterSet(AttributeFiltersMixin, NetBoxModelFilterSet): + profile_id = django_filters.ModelMultipleChoiceFilter( + queryset=ModuleTypeProfile.objects.all(), + label=_('Profile (ID)'), + ) + profile = django_filters.ModelMultipleChoiceFilter( + field_name='profile__name', + queryset=ModuleTypeProfile.objects.all(), + to_field_name='name', + label=_('Profile (name)'), + ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), label=_('Manufacturer (ID)'), @@ -921,6 +949,29 @@ class DeviceRoleFilterSet(OrganizationalModelFilterSet): queryset=ConfigTemplate.objects.all(), label=_('Config template (ID)'), ) + parent_id = django_filters.ModelMultipleChoiceFilter( + queryset=DeviceRole.objects.all(), + label=_('Parent device role (ID)'), + ) + parent = django_filters.ModelMultipleChoiceFilter( + field_name='parent__slug', + queryset=DeviceRole.objects.all(), + to_field_name='slug', + label=_('Parent device role (slug)'), + ) + ancestor_id = TreeNodeMultipleChoiceFilter( + queryset=DeviceRole.objects.all(), + field_name='parent', + lookup_expr='in', + label=_('Parent device role (ID)'), + ) + ancestor = TreeNodeMultipleChoiceFilter( + queryset=DeviceRole.objects.all(), + field_name='parent', + lookup_expr='in', + to_field_name='slug', + label=_('Parent device role (slug)'), + ) class Meta: model = DeviceRole @@ -989,14 +1040,16 @@ class DeviceFilterSet( queryset=DeviceType.objects.all(), label=_('Device type (ID)'), ) - role_id = django_filters.ModelMultipleChoiceFilter( - field_name='role_id', + role_id = TreeNodeMultipleChoiceFilter( + field_name='role', queryset=DeviceRole.objects.all(), + lookup_expr='in', label=_('Role (ID)'), ) - role = django_filters.ModelMultipleChoiceFilter( - field_name='role__slug', + role = TreeNodeMultipleChoiceFilter( queryset=DeviceRole.objects.all(), + field_name='role', + lookup_expr='in', to_field_name='slug', label=_('Role (slug)'), ) @@ -1591,11 +1644,15 @@ class PowerOutletFilterSet( queryset=PowerPort.objects.all(), label=_('Power port (ID)'), ) + status = django_filters.MultipleChoiceFilter( + choices=PowerOutletStatusChoices, + null_value=None + ) class Meta: model = PowerOutlet fields = ( - 'id', 'name', 'label', 'feed_leg', 'description', 'color', 'mark_connected', 'cable_end', + 'id', 'name', 'status', 'label', 'feed_leg', 'description', 'color', 'mark_connected', 'cable_end', ) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index da5a45f152b..dd6c4a791aa 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -14,7 +14,9 @@ from netbox.forms import NetBoxModelBulkEditForm from tenancy.models import Tenant from users.models import User from utilities.forms import BulkEditForm, add_blank_choice, form_from_model -from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField +from utilities.forms.fields import ( + ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, +) from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions from virtualization.models import Cluster @@ -46,6 +48,7 @@ __all__ = ( 'ModuleBayBulkEditForm', 'ModuleBayTemplateBulkEditForm', 'ModuleTypeBulkEditForm', + 'ModuleTypeProfileBulkEditForm', 'PlatformBulkEditForm', 'PowerFeedBulkEditForm', 'PowerOutletBulkEditForm', @@ -78,12 +81,13 @@ class RegionBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField() model = Region fieldsets = ( FieldSet('parent', 'description'), ) - nullable_fields = ('parent', 'description') + nullable_fields = ('parent', 'description', 'comments') class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): @@ -97,12 +101,13 @@ class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField() model = SiteGroup fieldsets = ( FieldSet('parent', 'description'), ) - nullable_fields = ('parent', 'description') + nullable_fields = ('parent', 'description', 'comments') class SiteBulkEditForm(NetBoxModelBulkEditForm): @@ -197,12 +202,13 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField() model = Location fieldsets = ( FieldSet('site', 'parent', 'status', 'tenant', 'description'), ) - nullable_fields = ('parent', 'tenant', 'description') + nullable_fields = ('parent', 'tenant', 'description', 'comments') class RackRoleBulkEditForm(NetBoxModelBulkEditForm): @@ -257,6 +263,11 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm): required=False, min_value=1 ) + outer_height = forms.IntegerField( + label=_('Outer height'), + required=False, + min_value=1 + ) outer_depth = forms.IntegerField( label=_('Outer depth'), required=False, @@ -299,7 +310,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm): fieldsets = ( FieldSet('manufacturer', 'description', 'form_factor', 'width', 'u_height', name=_('Rack Type')), FieldSet( - InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), + InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), 'mounting_depth', name=_('Dimensions') @@ -307,7 +318,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm): FieldSet('starting_unit', 'desc_units', name=_('Numbering')), ) nullable_fields = ( - 'outer_width', 'outer_depth', 'outer_unit', 'weight', + 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', ) @@ -401,6 +412,11 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): required=False, min_value=1 ) + outer_height = forms.IntegerField( + label=_('Outer height'), + required=False, + min_value=1 + ) outer_depth = forms.IntegerField( label=_('Outer depth'), required=False, @@ -448,15 +464,13 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): fieldsets = ( FieldSet('status', 'role', 'tenant', 'serial', 'asset_tag', 'rack_type', 'description', name=_('Rack')), FieldSet('region', 'site_group', 'site', 'location', name=_('Location')), - FieldSet( - 'form_factor', 'width', 'u_height', 'desc_units', 'airflow', 'outer_width', 'outer_depth', 'outer_unit', - 'mounting_depth', name=_('Hardware') - ), + FieldSet('outer_width', 'outer_height', 'outer_depth', 'outer_unit', name=_('Outer Dimensions')), + FieldSet('form_factor', 'width', 'u_height', 'desc_units', 'airflow', 'mounting_depth', name=_('Hardware')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), ) nullable_fields = ( - 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight', - 'max_weight', 'weight_unit', 'description', 'comments', + 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_height', 'outer_depth', + 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', ) @@ -563,7 +577,31 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments') +class ModuleTypeProfileBulkEditForm(NetBoxModelBulkEditForm): + schema = JSONField( + label=_('Schema'), + required=False + ) + description = forms.CharField( + label=_('Description'), + max_length=200, + required=False + ) + comments = CommentField() + + model = ModuleTypeProfile + fieldsets = ( + FieldSet('name', 'description', 'schema', name=_('Profile')), + ) + nullable_fields = ('description', 'comments') + + class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): + profile = DynamicModelChoiceField( + label=_('Profile'), + queryset=ModuleTypeProfile.objects.all(), + required=False + ) manufacturer = DynamicModelChoiceField( label=_('Manufacturer'), queryset=Manufacturer.objects.all(), @@ -598,17 +636,22 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): model = ModuleType fieldsets = ( - FieldSet('manufacturer', 'part_number', 'description', name=_('Module Type')), + FieldSet('profile', 'manufacturer', 'part_number', 'description', name=_('Module Type')), FieldSet( 'airflow', InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), name=_('Chassis') ), ) - nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments') + nullable_fields = ('part_number', 'weight', 'weight_unit', 'profile', 'description', 'comments') class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): + parent = DynamicModelChoiceField( + label=_('Parent'), + queryset=DeviceRole.objects.all(), + required=False, + ) color = ColorField( label=_('Color'), required=False @@ -628,12 +671,13 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField() model = DeviceRole fieldsets = ( - FieldSet('color', 'vm_role', 'config_template', 'description'), + FieldSet('parent', 'color', 'vm_role', 'config_template', 'description'), ) - nullable_fields = ('color', 'config_template', 'description') + nullable_fields = ('parent', 'color', 'config_template', 'description', 'comments') class PlatformBulkEditForm(NetBoxModelBulkEditForm): @@ -1379,7 +1423,10 @@ class PowerPortBulkEditForm( class PowerOutletBulkEditForm( ComponentBulkEditForm, - form_from_model(PowerOutlet, ['label', 'type', 'color', 'feed_leg', 'power_port', 'mark_connected', 'description']) + form_from_model( + PowerOutlet, + ['label', 'type', 'status', 'color', 'feed_leg', 'power_port', 'mark_connected', 'description'] + ) ): mark_connected = forms.NullBooleanField( label=_('Mark connected'), @@ -1389,7 +1436,7 @@ class PowerOutletBulkEditForm( model = PowerOutlet fieldsets = ( - FieldSet('module', 'type', 'label', 'description', 'mark_connected', 'color'), + FieldSet('module', 'type', 'label', 'status', 'description', 'mark_connected', 'color'), FieldSet('feed_leg', 'power_port', name=_('Power')), ) nullable_fields = ('module', 'label', 'type', 'feed_leg', 'power_port', 'description') diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index 92f7220da91..d412694b37a 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -39,6 +39,7 @@ __all__ = ( 'ModuleImportForm', 'ModuleBayImportForm', 'ModuleTypeImportForm', + 'ModuleTypeProfileImportForm', 'PlatformImportForm', 'PowerFeedImportForm', 'PowerOutletImportForm', @@ -68,7 +69,7 @@ class RegionImportForm(NetBoxModelImportForm): class Meta: model = Region - fields = ('name', 'slug', 'parent', 'description', 'tags') + fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments') class SiteGroupImportForm(NetBoxModelImportForm): @@ -82,7 +83,7 @@ class SiteGroupImportForm(NetBoxModelImportForm): class Meta: model = SiteGroup - fields = ('name', 'slug', 'parent', 'description') + fields = ('name', 'slug', 'parent', 'description', 'comments', 'tags') class SiteImportForm(NetBoxModelImportForm): @@ -160,7 +161,10 @@ class LocationImportForm(NetBoxModelImportForm): class Meta: model = Location - fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', 'tags') + fields = ( + 'site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', + 'tags', 'comments', + ) def __init__(self, data=None, *args, **kwargs): super().__init__(data, *args, **kwargs) @@ -219,7 +223,7 @@ class RackTypeImportForm(NetBoxModelImportForm): model = RackType fields = ( 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', - 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', + 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', ) @@ -304,7 +308,7 @@ class RackImportForm(NetBoxModelImportForm): model = Rack fields = ( 'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'rack_type', 'form_factor', 'serial', - 'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', + 'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', ) @@ -424,7 +428,22 @@ class DeviceTypeImportForm(NetBoxModelImportForm): ] +class ModuleTypeProfileImportForm(NetBoxModelImportForm): + + class Meta: + model = ModuleTypeProfile + fields = [ + 'name', 'description', 'schema', 'comments', 'tags', + ] + + class ModuleTypeImportForm(NetBoxModelImportForm): + profile = forms.ModelChoiceField( + label=_('Profile'), + queryset=ModuleTypeProfile.objects.all(), + to_field_name='name', + required=False + ) manufacturer = forms.ModelChoiceField( label=_('Manufacturer'), queryset=Manufacturer.objects.all(), @@ -457,6 +476,16 @@ class ModuleTypeImportForm(NetBoxModelImportForm): class DeviceRoleImportForm(NetBoxModelImportForm): + parent = CSVModelChoiceField( + label=_('Parent'), + queryset=DeviceRole.objects.all(), + required=False, + to_field_name='name', + help_text=_('Parent Device Role'), + error_messages={ + 'invalid_choice': _('Device role not found.'), + } + ) config_template = CSVModelChoiceField( label=_('Config template'), queryset=ConfigTemplate.objects.all(), @@ -468,7 +497,9 @@ class DeviceRoleImportForm(NetBoxModelImportForm): class Meta: model = DeviceRole - fields = ('name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags') + fields = ( + 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'comments', 'tags' + ) class PlatformImportForm(NetBoxModelImportForm): diff --git a/netbox/dcim/forms/common.py b/netbox/dcim/forms/common.py index 8ca258f3489..23109f66beb 100644 --- a/netbox/dcim/forms/common.py +++ b/netbox/dcim/forms/common.py @@ -43,20 +43,14 @@ class InterfaceCommonForm(forms.Form): super().clean() parent_field = 'device' if 'device' in self.cleaned_data else 'virtual_machine' - tagged_vlans = self.cleaned_data.get('tagged_vlans') - - # Untagged interfaces cannot be assigned tagged VLANs - if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans: - raise forms.ValidationError({ - 'mode': _("An access interface cannot have tagged VLANs assigned.") - }) - - # Remove all tagged VLAN assignments from "tagged all" interfaces - elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL: - self.cleaned_data['tagged_vlans'] = [] + if 'tagged_vlans' in self.fields.keys(): + tagged_vlans = self.cleaned_data.get('tagged_vlans') if self.is_bound else \ + self.get_initial_for_field(self.fields['tagged_vlans'], 'tagged_vlans') + else: + tagged_vlans = [] # Validate tagged VLANs; must be a global VLAN or in the same site - elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED and tagged_vlans: + if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED and tagged_vlans: valid_sites = [None, self.cleaned_data[parent_field].site] invalid_vlans = [str(v) for v in tagged_vlans if v.site not in valid_sites] diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 37b8afd1747..8465f6404ec 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -39,6 +39,7 @@ __all__ = ( 'ModuleFilterForm', 'ModuleBayFilterForm', 'ModuleTypeFilterForm', + 'ModuleTypeProfileFilterForm', 'PlatformFilterForm', 'PowerConnectionFilterForm', 'PowerFeedFilterForm', @@ -602,11 +603,19 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm): ) +class ModuleTypeProfileFilterForm(NetBoxModelFilterSetForm): + model = ModuleTypeProfile + fieldsets = ( + FieldSet('q', 'filter_id', 'tag'), + ) + selector_fields = ('filter_id', 'q') + + class ModuleTypeFilterForm(NetBoxModelFilterSetForm): model = ModuleType fieldsets = ( FieldSet('q', 'filter_id', 'tag'), - FieldSet('manufacturer_id', 'part_number', 'airflow', name=_('Hardware')), + FieldSet('profile_id', 'manufacturer_id', 'part_number', 'airflow', name=_('Hardware')), FieldSet( 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports', name=_('Components') @@ -614,6 +623,11 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm): FieldSet('weight', 'weight_unit', name=_('Weight')), ) selector_fields = ('filter_id', 'q', 'manufacturer_id') + profile_id = DynamicModelMultipleChoiceField( + queryset=ModuleTypeProfile.objects.all(), + required=False, + label=_('Profile') + ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), required=False, @@ -689,6 +703,11 @@ class DeviceRoleFilterForm(NetBoxModelFilterSetForm): required=False, label=_('Config template') ) + parent_id = DynamicModelMultipleChoiceField( + queryset=DeviceRole.objects.all(), + required=False, + label=_('Parent') + ) tag = TagFilterField(model) @@ -1305,7 +1324,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = PowerOutlet fieldsets = ( FieldSet('q', 'filter_id', 'tag'), - FieldSet('name', 'label', 'type', 'color', name=_('Attributes')), + FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id', @@ -1323,6 +1342,11 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): label=_('Color'), required=False ) + status = forms.MultipleChoiceField( + label=_('Status'), + choices=PowerOutletStatusChoices, + required=False + ) class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 5a3a27d25e8..ac9b0ea9af3 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.contenttypes.models import ContentType +from django.core.validators import EMPTY_VALUES from django.utils.translation import gettext_lazy as _ from timezone_field import TimeZoneFormField @@ -18,6 +19,7 @@ from utilities.forms.fields import ( ) from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups from utilities.forms.widgets import APISelect, ClearableFileInput, HTMXSelect, NumberWithOptions, SelectWithPK +from utilities.jsonschema import JSONSchemaProperty from virtualization.models import Cluster, VMInterface from wireless.models import WirelessLAN, WirelessLANGroup from .common import InterfaceCommonForm, ModuleCommonForm @@ -48,6 +50,7 @@ __all__ = ( 'ModuleBayForm', 'ModuleBayTemplateForm', 'ModuleTypeForm', + 'ModuleTypeProfileForm', 'PlatformForm', 'PopulateDeviceBayForm', 'PowerFeedForm', @@ -78,6 +81,7 @@ class RegionForm(NetBoxModelForm): required=False ) slug = SlugField() + comments = CommentField() fieldsets = ( FieldSet('parent', 'name', 'slug', 'description', 'tags'), @@ -86,7 +90,7 @@ class RegionForm(NetBoxModelForm): class Meta: model = Region fields = ( - 'parent', 'name', 'slug', 'description', 'tags', + 'parent', 'name', 'slug', 'description', 'tags', 'comments', ) @@ -97,6 +101,7 @@ class SiteGroupForm(NetBoxModelForm): required=False ) slug = SlugField() + comments = CommentField() fieldsets = ( FieldSet('parent', 'name', 'slug', 'description', 'tags'), @@ -105,7 +110,7 @@ class SiteGroupForm(NetBoxModelForm): class Meta: model = SiteGroup fields = ( - 'parent', 'name', 'slug', 'description', 'tags', + 'parent', 'name', 'slug', 'description', 'comments', 'tags', ) @@ -179,6 +184,7 @@ class LocationForm(TenancyForm, NetBoxModelForm): } ) slug = SlugField() + comments = CommentField() fieldsets = ( FieldSet('site', 'parent', 'name', 'slug', 'status', 'facility', 'description', 'tags', name=_('Location')), @@ -188,7 +194,8 @@ class LocationForm(TenancyForm, NetBoxModelForm): class Meta: model = Location fields = ( - 'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'facility', 'tags', + 'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', + 'facility', 'tags', 'comments', ) @@ -222,7 +229,7 @@ class RackTypeForm(NetBoxModelForm): FieldSet('manufacturer', 'model', 'slug', 'description', 'form_factor', 'tags', name=_('Rack Type')), FieldSet( 'width', 'u_height', - InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), + InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), 'mounting_depth', name=_('Dimensions') ), @@ -233,8 +240,8 @@ class RackTypeForm(NetBoxModelForm): model = RackType fields = [ 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', - 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', - 'description', 'comments', 'tags', + 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', + 'weight_unit', 'description', 'comments', 'tags', ] @@ -279,8 +286,8 @@ class RackForm(TenancyForm, NetBoxModelForm): fields = [ 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', - 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', - 'description', 'comments', 'tags', + 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', + 'weight_unit', 'description', 'comments', 'tags', ] def __init__(self, *args, **kwargs): @@ -302,7 +309,8 @@ class RackForm(TenancyForm, NetBoxModelForm): *self.fieldsets, FieldSet( 'form_factor', 'width', 'starting_unit', 'u_height', - InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), + InlineFields('outer_width', 'outer_height', 'outer_depth', 'outer_unit', + label=_('Outer Dimensions')), InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), 'mounting_depth', 'desc_units', name=_('Dimensions') ), @@ -399,25 +407,104 @@ class DeviceTypeForm(NetBoxModelForm): } +class ModuleTypeProfileForm(NetBoxModelForm): + schema = JSONField( + label=_('Schema'), + required=False, + help_text=_("Enter a valid JSON schema to define supported attributes.") + ) + comments = CommentField() + + fieldsets = ( + FieldSet('name', 'description', 'schema', 'tags', name=_('Profile')), + ) + + class Meta: + model = ModuleTypeProfile + fields = [ + 'name', 'description', 'schema', 'comments', 'tags', + ] + + class ModuleTypeForm(NetBoxModelForm): + profile = forms.ModelChoiceField( + queryset=ModuleTypeProfile.objects.all(), + label=_('Profile'), + required=False, + widget=HTMXSelect() + ) manufacturer = DynamicModelChoiceField( label=_('Manufacturer'), queryset=Manufacturer.objects.all() ) comments = CommentField() - fieldsets = ( - FieldSet('manufacturer', 'model', 'part_number', 'description', 'tags', name=_('Module Type')), - FieldSet('airflow', 'weight', 'weight_unit', name=_('Chassis')) - ) + @property + def fieldsets(self): + return [ + FieldSet('manufacturer', 'model', 'part_number', 'description', 'tags', name=_('Module Type')), + FieldSet('airflow', 'weight', 'weight_unit', name=_('Hardware')), + FieldSet('profile', *self.attr_fields, name=_('Profile & Attributes')) + ] class Meta: model = ModuleType fields = [ - 'manufacturer', 'model', 'part_number', 'airflow', 'weight', 'weight_unit', 'description', + 'profile', 'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'comments', 'tags', ] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Track profile-specific attribute fields + self.attr_fields = [] + + # Retrieve assigned ModuleTypeProfile, if any + if not (profile_id := get_field_value(self, 'profile')): + return + if not (profile := ModuleTypeProfile.objects.filter(pk=profile_id).first()): + return + + # Extend form with fields for profile attributes + for attr, form_field in self._get_attr_form_fields(profile).items(): + field_name = f'attr_{attr}' + self.attr_fields.append(field_name) + self.fields[field_name] = form_field + if self.instance.attribute_data: + self.fields[field_name].initial = self.instance.attribute_data.get(attr) + + @staticmethod + def _get_attr_form_fields(profile): + """ + Return a dictionary mapping of attribute names to form fields, suitable for extending + the form per the selected ModuleTypeProfile. + """ + if not profile.schema: + return {} + + properties = profile.schema.get('properties', {}) + required_fields = profile.schema.get('required', []) + + attr_fields = {} + for name, options in properties.items(): + prop = JSONSchemaProperty(**options) + attr_fields[name] = prop.to_form_field(name, required=name in required_fields) + + return dict(sorted(attr_fields.items())) + + def _post_clean(self): + + # Compile attribute data from the individual form fields + if self.cleaned_data.get('profile'): + self.instance.attribute_data = { + name[5:]: self.cleaned_data[name] # Remove the attr_ prefix + for name in self.attr_fields + if self.cleaned_data.get(name) not in EMPTY_VALUES + } + + return super()._post_clean() + class DeviceRoleForm(NetBoxModelForm): config_template = DynamicModelChoiceField( @@ -426,17 +513,24 @@ class DeviceRoleForm(NetBoxModelForm): required=False ) slug = SlugField() + parent = DynamicModelChoiceField( + label=_('Parent'), + queryset=DeviceRole.objects.all(), + required=False, + ) + comments = CommentField() fieldsets = ( FieldSet( - 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', name=_('Device Role') + 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', + 'tags', name=_('Device Role') ), ) class Meta: model = DeviceRole fields = [ - 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', + 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'comments', 'tags', ] @@ -1308,7 +1402,7 @@ class PowerOutletForm(ModularDeviceComponentForm): fieldsets = ( FieldSet( - 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', + 'device', 'module', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'mark_connected', 'description', 'tags', ), ) @@ -1316,7 +1410,7 @@ class PowerOutletForm(ModularDeviceComponentForm): class Meta: model = PowerOutlet fields = [ - 'device', 'module', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'mark_connected', + 'device', 'module', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'mark_connected', 'description', 'tags', ] diff --git a/netbox/dcim/graphql/enums.py b/netbox/dcim/graphql/enums.py new file mode 100644 index 00000000000..a60c0df14ac --- /dev/null +++ b/netbox/dcim/graphql/enums.py @@ -0,0 +1,77 @@ +import strawberry + +from dcim.choices import * + +__all__ = ( + 'CableEndEnum', + 'CableLengthUnitEnum', + 'CableTypeEnum', + 'ConsolePortSpeedEnum', + 'ConsolePortTypeEnum', + 'DeviceAirflowEnum', + 'DeviceFaceEnum', + 'DeviceStatusEnum', + 'InterfaceDuplexEnum', + 'InterfaceModeEnum', + 'InterfacePoEModeEnum', + 'InterfacePoETypeEnum', + 'InterfaceSpeedEnum', + 'InterfaceTypeEnum', + 'InventoryItemStatusEnum', + 'LinkStatusEnum', + 'LocationStatusEnum', + 'ModuleAirflowEnum', + 'ModuleStatusEnum', + 'PortTypeEnum', + 'PowerFeedPhaseEnum', + 'PowerFeedStatusEnum', + 'PowerFeedSupplyEnum', + 'PowerFeedTypeEnum', + 'PowerOutletFeedLegEnum', + 'PowerOutletTypeEnum', + 'PowerPortTypeEnum', + 'RackAirflowEnum', + 'RackDimensionUnitEnum', + 'RackFormFactorEnum', + 'RackStatusEnum', + 'RackWidthEnum', + 'SiteStatusEnum', + 'SubdeviceRoleEnum', + 'VirtualDeviceContextStatusEnum', +) + +CableEndEnum = strawberry.enum(CableEndChoices.as_enum()) +CableLengthUnitEnum = strawberry.enum(CableLengthUnitChoices.as_enum()) +CableTypeEnum = strawberry.enum(CableTypeChoices.as_enum()) +ConsolePortSpeedEnum = strawberry.enum(ConsolePortSpeedChoices.as_enum()) +ConsolePortTypeEnum = strawberry.enum(ConsolePortTypeChoices.as_enum()) +DeviceAirflowEnum = strawberry.enum(DeviceAirflowChoices.as_enum()) +DeviceFaceEnum = strawberry.enum(DeviceFaceChoices.as_enum()) +DeviceStatusEnum = strawberry.enum(DeviceStatusChoices.as_enum()) +InterfaceDuplexEnum = strawberry.enum(InterfaceDuplexChoices.as_enum()) +InterfaceModeEnum = strawberry.enum(InterfaceModeChoices.as_enum()) +InterfacePoEModeEnum = strawberry.enum(InterfacePoEModeChoices.as_enum()) +InterfacePoETypeEnum = strawberry.enum(InterfacePoETypeChoices.as_enum()) +InterfaceSpeedEnum = strawberry.enum(InterfaceSpeedChoices.as_enum()) +InterfaceTypeEnum = strawberry.enum(InterfaceTypeChoices.as_enum()) +InventoryItemStatusEnum = strawberry.enum(InventoryItemStatusChoices.as_enum()) +LinkStatusEnum = strawberry.enum(LinkStatusChoices.as_enum()) +LocationStatusEnum = strawberry.enum(LocationStatusChoices.as_enum()) +ModuleAirflowEnum = strawberry.enum(ModuleAirflowChoices.as_enum()) +ModuleStatusEnum = strawberry.enum(ModuleStatusChoices.as_enum()) +PortTypeEnum = strawberry.enum(PortTypeChoices.as_enum()) +PowerFeedPhaseEnum = strawberry.enum(PowerFeedPhaseChoices.as_enum()) +PowerFeedStatusEnum = strawberry.enum(PowerFeedStatusChoices.as_enum()) +PowerFeedSupplyEnum = strawberry.enum(PowerFeedSupplyChoices.as_enum()) +PowerFeedTypeEnum = strawberry.enum(PowerFeedTypeChoices.as_enum()) +PowerOutletFeedLegEnum = strawberry.enum(PowerOutletFeedLegChoices.as_enum()) +PowerOutletTypeEnum = strawberry.enum(PowerOutletTypeChoices.as_enum()) +PowerPortTypeEnum = strawberry.enum(PowerPortTypeChoices.as_enum()) +RackAirflowEnum = strawberry.enum(RackAirflowChoices.as_enum()) +RackDimensionUnitEnum = strawberry.enum(RackDimensionUnitChoices.as_enum()) +RackFormFactorEnum = strawberry.enum(RackFormFactorChoices.as_enum()) +RackStatusEnum = strawberry.enum(RackStatusChoices.as_enum()) +RackWidthEnum = strawberry.enum(RackWidthChoices.as_enum()) +SiteStatusEnum = strawberry.enum(SiteStatusChoices.as_enum()) +SubdeviceRoleEnum = strawberry.enum(SubdeviceRoleChoices.as_enum()) +VirtualDeviceContextStatusEnum = strawberry.enum(VirtualDeviceContextStatusChoices.as_enum()) diff --git a/netbox/dcim/graphql/filter_mixins.py b/netbox/dcim/graphql/filter_mixins.py new file mode 100644 index 00000000000..47a75d08e11 --- /dev/null +++ b/netbox/dcim/graphql/filter_mixins.py @@ -0,0 +1,149 @@ +from dataclasses import dataclass +from typing import Annotated, TYPE_CHECKING + +import strawberry +import strawberry_django +from strawberry import ID +from strawberry_django import FilterLookup + +from core.graphql.filter_mixins import BaseFilterMixin, ChangeLogFilterMixin +from core.graphql.filters import ContentTypeFilter +from netbox.graphql.filter_mixins import NetBoxModelFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin +from .enums import * + +if TYPE_CHECKING: + from netbox.graphql.filter_lookups import IntegerLookup + from extras.graphql.filters import ConfigTemplateFilter + from ipam.graphql.filters import VLANFilter, VLANTranslationPolicyFilter + from .filters import * + +__all__ = ( + 'CabledObjectModelFilterMixin', + 'ComponentModelFilterMixin', + 'ComponentTemplateFilterMixin', + 'InterfaceBaseFilterMixin', + 'ModularComponentModelFilterMixin', + 'ModularComponentTemplateFilterMixin', + 'RackBaseFilterMixin', + 'RenderConfigFilterMixin', + 'ScopedFilterMixin', +) + + +@dataclass +class ScopedFilterMixin(BaseFilterMixin): + scope_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + scope_id: ID | None = strawberry_django.filter_field() + + +@dataclass +class ComponentModelFilterMixin(NetBoxModelFilterMixin): + device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + device_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + label: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + + +@dataclass +class ModularComponentModelFilterMixin(ComponentModelFilterMixin): + module: Annotated['ModuleFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + module_id: ID | None = strawberry_django.filter_field() + inventory_items: Annotated['InventoryItemFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class CabledObjectModelFilterMixin(BaseFilterMixin): + cable: Annotated['CableFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + cable_id: ID | None = strawberry_django.filter_field() + cable_end: CableEndEnum | None = strawberry_django.filter_field() + mark_connected: FilterLookup[bool] | None = strawberry_django.filter_field() + + +@dataclass +class ComponentTemplateFilterMixin(ChangeLogFilterMixin): + device_type: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + device_type_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + label: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + + +@dataclass +class ModularComponentTemplateFilterMixin(ComponentTemplateFilterMixin): + module_type: Annotated['ModuleTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class RenderConfigFilterMixin(BaseFilterMixin): + config_template: Annotated['ConfigTemplateFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + config_template_id: ID | None = strawberry_django.filter_field() + + +@dataclass +class InterfaceBaseFilterMixin(BaseFilterMixin): + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + mtu: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + mode: InterfaceModeEnum | None = strawberry_django.filter_field() + parent: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + parent_id: ID | None = strawberry_django.filter_field() + bridge: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + bridge_id: ID | None = strawberry_django.filter_field() + untagged_vlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + tagged_vlans: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + qinq_svlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vlan_translation_policy: Annotated['VLANTranslationPolicyFilter', strawberry.lazy('ipam.graphql.filters')] | None \ + = strawberry_django.filter_field() + primary_mac_address: Annotated['MACAddressFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + primary_mac_address_id: ID | None = strawberry_django.filter_field() + + +@dataclass +class RackBaseFilterMixin(WeightFilterMixin, PrimaryModelFilterMixin): + width: Annotated['RackWidthEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + u_height: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + starting_unit: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + desc_units: FilterLookup[bool] | None = strawberry_django.filter_field() + outer_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + outer_depth: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + outer_unit: Annotated['RackDimensionUnitEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + mounting_depth: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + max_weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) diff --git a/netbox/dcim/graphql/filters.py b/netbox/dcim/graphql/filters.py index 94f2c6d38a6..5dfc0d73cd4 100644 --- a/netbox/dcim/graphql/filters.py +++ b/netbox/dcim/graphql/filters.py @@ -1,7 +1,46 @@ -import strawberry_django +from typing import Annotated, TYPE_CHECKING -from dcim import filtersets, models -from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin +import strawberry +import strawberry_django +from strawberry.scalars import ID +from strawberry_django import FilterLookup + +from core.graphql.filter_mixins import ChangeLogFilterMixin +from dcim import models +from extras.graphql.filter_mixins import ConfigContextFilterMixin +from netbox.graphql.filter_mixins import ( + PrimaryModelFilterMixin, + OrganizationalModelFilterMixin, + NestedGroupModelFilterMixin, + ImageAttachmentFilterMixin, + WeightFilterMixin, +) +from tenancy.graphql.filter_mixins import TenancyFilterMixin, ContactFilterMixin +from .filter_mixins import ( + CabledObjectModelFilterMixin, + ComponentModelFilterMixin, + ComponentTemplateFilterMixin, + InterfaceBaseFilterMixin, + ModularComponentModelFilterMixin, + ModularComponentTemplateFilterMixin, + RackBaseFilterMixin, + RenderConfigFilterMixin, +) + +if TYPE_CHECKING: + from core.graphql.filters import ContentTypeFilter + from extras.graphql.filters import ConfigTemplateFilter, ImageAttachmentFilter + from ipam.graphql.filters import ( + ASNFilter, FHRPGroupAssignmentFilter, IPAddressFilter, PrefixFilter, VLANGroupFilter, VRFFilter, + ) + from netbox.graphql.enums import ColorEnum + from netbox.graphql.filter_lookups import FloatLookup, IntegerArrayLookup, IntegerLookup, TreeNodeFilter + from users.graphql.filters import UserFilter + from virtualization.graphql.filters import ClusterFilter + from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter + from wireless.graphql.enums import WirelessChannelEnum, WirelessRoleEnum + from wireless.graphql.filters import WirelessLANFilter, WirelessLinkFilter + from .enums import * __all__ = ( 'CableFilter', @@ -13,7 +52,6 @@ __all__ = ( 'DeviceFilter', 'DeviceBayFilter', 'DeviceBayTemplateFilter', - 'InventoryItemTemplateFilter', 'DeviceRoleFilter', 'DeviceTypeFilter', 'FrontPortFilter', @@ -22,6 +60,7 @@ __all__ = ( 'InterfaceTemplateFilter', 'InventoryItemFilter', 'InventoryItemRoleFilter', + 'InventoryItemTemplateFilter', 'LocationFilter', 'MACAddressFilter', 'ManufacturerFilter', @@ -29,6 +68,7 @@ __all__ = ( 'ModuleBayFilter', 'ModuleBayTemplateFilter', 'ModuleTypeFilter', + 'ModuleTypeProfileFilter', 'PlatformFilter', 'PowerFeedFilter', 'PowerOutletFilter', @@ -51,258 +91,768 @@ __all__ = ( @strawberry_django.filter(models.Cable, lookups=True) -@autotype_decorator(filtersets.CableFilterSet) -class CableFilter(BaseFilterMixin): - pass +class CableFilter(PrimaryModelFilterMixin, TenancyFilterMixin): + type: Annotated['CableTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + status: Annotated['LinkStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + label: FilterLookup[str] | None = strawberry_django.filter_field() + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + length: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + length_unit: Annotated['CableLengthUnitEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + terminations: Annotated['CableTerminationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.CableTermination, lookups=True) -@autotype_decorator(filtersets.CableTerminationFilterSet) -class CableTerminationFilter(BaseFilterMixin): - pass +class CableTerminationFilter(ChangeLogFilterMixin): + cable: Annotated['CableFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + cable_id: ID | None = strawberry_django.filter_field() + cable_end: Annotated['CableEndEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + termination_type: Annotated['CableTerminationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + termination_id: ID | None = strawberry_django.filter_field() @strawberry_django.filter(models.ConsolePort, lookups=True) -@autotype_decorator(filtersets.ConsolePortFilterSet) -class ConsolePortFilter(BaseFilterMixin): - pass +class ConsolePortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + speed: Annotated['ConsolePortSpeedEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ConsolePortTemplate, lookups=True) -@autotype_decorator(filtersets.ConsolePortTemplateFilterSet) -class ConsolePortTemplateFilter(BaseFilterMixin): - pass +class ConsolePortTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ConsoleServerPort, lookups=True) -@autotype_decorator(filtersets.ConsoleServerPortFilterSet) -class ConsoleServerPortFilter(BaseFilterMixin): - pass +class ConsoleServerPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + speed: Annotated['ConsolePortSpeedEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ConsoleServerPortTemplate, lookups=True) -@autotype_decorator(filtersets.ConsoleServerPortTemplateFilterSet) -class ConsoleServerPortTemplateFilter(BaseFilterMixin): - pass +class ConsoleServerPortTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Device, lookups=True) -@autotype_decorator(filtersets.DeviceFilterSet) -class DeviceFilter(BaseFilterMixin): - pass +class DeviceFilter( + ContactFilterMixin, + TenancyFilterMixin, + ImageAttachmentFilterMixin, + RenderConfigFilterMixin, + ConfigContextFilterMixin, + PrimaryModelFilterMixin, +): + device_type: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + device_type_id: ID | None = strawberry_django.filter_field() + role: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + role_id: ID | None = strawberry_django.filter_field() + platform: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() + serial: FilterLookup[str] | None = strawberry_django.filter_field() + asset_tag: FilterLookup[str] | None = strawberry_django.filter_field() + site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + site_id: ID | None = strawberry_django.filter_field() + location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + rack_id: ID | None = strawberry_django.filter_field() + position: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + face: Annotated['DeviceFaceEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + status: Annotated['DeviceStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + airflow: Annotated['DeviceAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + primary_ip4: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + primary_ip4_id: ID | None = strawberry_django.filter_field() + primary_ip6: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + primary_ip6_id: ID | None = strawberry_django.filter_field() + oob_ip: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + oob_ip_id: ID | None = strawberry_django.filter_field() + cluster: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + cluster_id: ID | None = strawberry_django.filter_field() + virtual_chassis: Annotated['VirtualChassisFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + virtual_chassis_id: ID | None = strawberry_django.filter_field() + vc_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + vc_priority: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + latitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + longitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + interfaces: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + consoleports: Annotated['ConsolePortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + consoleserverports: Annotated['ConsoleServerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + poweroutlets: Annotated['PowerOutletFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + powerports: Annotated['PowerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + devicebays: Annotated['DeviceBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + frontports: Annotated['FrontPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + rearports: Annotated['RearPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + modulebays: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + modules: Annotated['ModuleFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + console_port_count: FilterLookup[int] | None = strawberry_django.filter_field() + console_server_port_count: FilterLookup[int] | None = strawberry_django.filter_field() + power_port_count: FilterLookup[int] | None = strawberry_django.filter_field() + power_outlet_count: FilterLookup[int] | None = strawberry_django.filter_field() + interface_count: FilterLookup[int] | None = strawberry_django.filter_field() + front_port_count: FilterLookup[int] | None = strawberry_django.filter_field() + rear_port_count: FilterLookup[int] | None = strawberry_django.filter_field() + device_bay_count: FilterLookup[int] | None = strawberry_django.filter_field() + module_bay_count: FilterLookup[int] | None = strawberry_django.filter_field() + inventory_item_count: FilterLookup[int] | None = strawberry_django.filter_field() @strawberry_django.filter(models.DeviceBay, lookups=True) -@autotype_decorator(filtersets.DeviceBayFilterSet) -class DeviceBayFilter(BaseFilterMixin): - pass +class DeviceBayFilter(ComponentModelFilterMixin): + installed_device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + installed_device_id: ID | None = strawberry_django.filter_field() @strawberry_django.filter(models.DeviceBayTemplate, lookups=True) -@autotype_decorator(filtersets.DeviceBayTemplateFilterSet) -class DeviceBayTemplateFilter(BaseFilterMixin): +class DeviceBayTemplateFilter(ComponentTemplateFilterMixin): pass @strawberry_django.filter(models.InventoryItemTemplate, lookups=True) -@autotype_decorator(filtersets.InventoryItemTemplateFilterSet) -class InventoryItemTemplateFilter(BaseFilterMixin): - pass +class InventoryItemTemplateFilter(ComponentTemplateFilterMixin): + parent: Annotated['InventoryItemTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + component_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + component_id: ID | None = strawberry_django.filter_field() + role: Annotated['InventoryItemRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + role_id: ID | None = strawberry_django.filter_field() + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + part_id: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.DeviceRole, lookups=True) -@autotype_decorator(filtersets.DeviceRoleFilterSet) -class DeviceRoleFilter(BaseFilterMixin): - pass +class DeviceRoleFilter(OrganizationalModelFilterMixin, RenderConfigFilterMixin): + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + vm_role: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.DeviceType, lookups=True) -@autotype_decorator(filtersets.DeviceTypeFilterSet) -class DeviceTypeFilter(BaseFilterMixin): - pass +class DeviceTypeFilter(ImageAttachmentFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin): + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + model: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + default_platform: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + default_platform_id: ID | None = strawberry_django.filter_field() + part_number: FilterLookup[str] | None = strawberry_django.filter_field() + u_height: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + exclude_from_utilization: FilterLookup[bool] | None = strawberry_django.filter_field() + is_full_depth: FilterLookup[bool] | None = strawberry_django.filter_field() + subdevice_role: Annotated['SubdeviceRoleEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + airflow: Annotated['DeviceAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + front_image: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + rear_image: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + console_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + console_server_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + power_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + power_outlet_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + interface_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + front_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + rear_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + device_bay_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + module_bay_template_count: FilterLookup[int] | None = strawberry_django.filter_field() + inventory_item_template_count: FilterLookup[int] | None = strawberry_django.filter_field() @strawberry_django.filter(models.FrontPort, lookups=True) -@autotype_decorator(filtersets.FrontPortFilterSet) -class FrontPortFilter(BaseFilterMixin): - pass +class FrontPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + rear_port: Annotated['RearPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + rear_port_id: ID | None = strawberry_django.filter_field() + rear_port_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.FrontPortTemplate, lookups=True) -@autotype_decorator(filtersets.FrontPortTemplateFilterSet) -class FrontPortTemplateFilter(BaseFilterMixin): - pass +class FrontPortTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + rear_port: Annotated['RearPortTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + rear_port_id: ID | None = strawberry_django.filter_field() + rear_port_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.MACAddress, lookups=True) -@autotype_decorator(filtersets.MACAddressFilterSet) -class MACAddressFilter(BaseFilterMixin): - pass +class MACAddressFilter(PrimaryModelFilterMixin): + mac_address: FilterLookup[str] | None = strawberry_django.filter_field() + assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + assigned_object_id: ID | None = strawberry_django.filter_field() @strawberry_django.filter(models.Interface, lookups=True) -@autotype_decorator(filtersets.InterfaceFilterSet) -class InterfaceFilter(BaseFilterMixin): - pass +class InterfaceFilter(ModularComponentModelFilterMixin, InterfaceBaseFilterMixin, CabledObjectModelFilterMixin): + vcdcs: Annotated['VirtualDeviceContextFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + lag: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + lag_id: ID | None = strawberry_django.filter_field() + type: Annotated['InterfaceTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + mgmt_only: FilterLookup[bool] | None = strawberry_django.filter_field() + speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + duplex: Annotated['InterfaceDuplexEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + wwn: FilterLookup[str] | None = strawberry_django.filter_field() + rf_role: Annotated['WirelessRoleEnum', strawberry.lazy('wireless.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + rf_channel: Annotated['WirelessChannelEnum', strawberry.lazy('wireless.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + rf_channel_frequency: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + rf_channel_width: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + tx_power: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + poe_mode: Annotated['InterfacePoEModeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + poe_type: Annotated['InterfacePoETypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + wireless_link: Annotated['WirelessLinkFilter', strawberry.lazy('wireless.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + wireless_link_id: ID | None = strawberry_django.filter_field() + wireless_lans: Annotated['WirelessLANFilter', strawberry.lazy('wireless.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + vrf_id: ID | None = strawberry_django.filter_field() + ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + mac_addresses: Annotated['MACAddressFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + fhrp_group_assignments: Annotated['FHRPGroupAssignmentFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + tunnel_terminations: Annotated['TunnelTerminationFilter', strawberry.lazy('vpn.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + l2vpn_terminations: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.InterfaceTemplate, lookups=True) -@autotype_decorator(filtersets.InterfaceTemplateFilterSet) -class InterfaceTemplateFilter(BaseFilterMixin): - pass +class InterfaceTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['InterfaceTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + mgmt_only: FilterLookup[bool] | None = strawberry_django.filter_field() + bridge: Annotated['InterfaceTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + bridge_id: ID | None = strawberry_django.filter_field() + poe_mode: Annotated['InterfacePoEModeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + poe_type: Annotated['InterfacePoETypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + rf_role: Annotated['WirelessRoleEnum', strawberry.lazy('wireless.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.InventoryItem, lookups=True) -@autotype_decorator(filtersets.InventoryItemFilterSet) -class InventoryItemFilter(BaseFilterMixin): - pass +class InventoryItemFilter(ComponentModelFilterMixin): + parent: Annotated['InventoryItemFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + parent_id: ID | None = strawberry_django.filter_field() + component_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + component_id: ID | None = strawberry_django.filter_field() + status: Annotated['InventoryItemStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + role: Annotated['InventoryItemRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + role_id: ID | None = strawberry_django.filter_field() + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + part_id: FilterLookup[str] | None = strawberry_django.filter_field() + serial: FilterLookup[str] | None = strawberry_django.filter_field() + asset_tag: FilterLookup[str] | None = strawberry_django.filter_field() + discovered: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.InventoryItemRole, lookups=True) -@autotype_decorator(filtersets.InventoryItemRoleFilterSet) -class InventoryItemRoleFilter(BaseFilterMixin): - pass +class InventoryItemRoleFilter(OrganizationalModelFilterMixin): + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Location, lookups=True) -@autotype_decorator(filtersets.LocationFilterSet) -class LocationFilter(BaseFilterMixin): - pass +class LocationFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, NestedGroupModelFilterMixin): + site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + site_id: ID | None = strawberry_django.filter_field() + status: Annotated['LocationStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + facility: FilterLookup[str] | None = strawberry_django.filter_field() + prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Manufacturer, lookups=True) -@autotype_decorator(filtersets.ManufacturerFilterSet) -class ManufacturerFilter(BaseFilterMixin): +class ManufacturerFilter(ContactFilterMixin, OrganizationalModelFilterMixin): pass @strawberry_django.filter(models.Module, lookups=True) -@autotype_decorator(filtersets.ModuleFilterSet) -class ModuleFilter(BaseFilterMixin): - pass +class ModuleFilter(PrimaryModelFilterMixin, ConfigContextFilterMixin): + device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + device_id: ID | None = strawberry_django.filter_field() + module_bay: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + module_bay_id: ID | None = strawberry_django.filter_field() + module_type: Annotated['ModuleTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + module_type_id: ID | None = strawberry_django.filter_field() + status: Annotated['ModuleStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + serial: FilterLookup[str] | None = strawberry_django.filter_field() + asset_tag: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ModuleBay, lookups=True) -@autotype_decorator(filtersets.ModuleBayFilterSet) -class ModuleBayFilter(BaseFilterMixin): - pass +class ModuleBayFilter(ModularComponentModelFilterMixin): + parent: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + parent_id: ID | None = strawberry_django.filter_field() + position: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ModuleBayTemplate, lookups=True) -@autotype_decorator(filtersets.ModuleBayTemplateFilterSet) -class ModuleBayTemplateFilter(BaseFilterMixin): - pass +class ModuleBayTemplateFilter(ModularComponentTemplateFilterMixin): + position: FilterLookup[str] | None = strawberry_django.filter_field() + + +@strawberry_django.filter(models.ModuleTypeProfile, lookups=True) +class ModuleTypeProfileFilter(PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ModuleType, lookups=True) -@autotype_decorator(filtersets.ModuleTypeFilterSet) -class ModuleTypeFilter(BaseFilterMixin): - pass +class ModuleTypeFilter(ImageAttachmentFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin): + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + model: FilterLookup[str] | None = strawberry_django.filter_field() + part_number: FilterLookup[str] | None = strawberry_django.filter_field() + airflow: Annotated['ModuleAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Platform, lookups=True) -@autotype_decorator(filtersets.PlatformFilterSet) -class PlatformFilter(BaseFilterMixin): - pass +class PlatformFilter(OrganizationalModelFilterMixin): + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + config_template: Annotated['ConfigTemplateFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + config_template_id: ID | None = strawberry_django.filter_field() @strawberry_django.filter(models.PowerFeed, lookups=True) -@autotype_decorator(filtersets.PowerFeedFilterSet) -class PowerFeedFilter(BaseFilterMixin): - pass +class PowerFeedFilter(CabledObjectModelFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + power_panel: Annotated['PowerPanelFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + power_panel_id: ID | None = strawberry_django.filter_field() + rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + rack_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + status: Annotated['PowerFeedStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + type: Annotated['PowerFeedTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + supply: Annotated['PowerFeedSupplyEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + phase: Annotated['PowerFeedPhaseEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + voltage: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + amperage: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + max_utilization: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + available_power: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.PowerOutlet, lookups=True) -@autotype_decorator(filtersets.PowerOutletFilterSet) -class PowerOutletFilter(BaseFilterMixin): - pass +class PowerOutletFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['PowerOutletTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + power_port: Annotated['PowerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + power_port_id: ID | None = strawberry_django.filter_field() + feed_leg: Annotated['PowerOutletFeedLegEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() @strawberry_django.filter(models.PowerOutletTemplate, lookups=True) -@autotype_decorator(filtersets.PowerOutletTemplateFilterSet) -class PowerOutletTemplateFilter(BaseFilterMixin): - pass +class PowerOutletTemplateFilter(ModularComponentModelFilterMixin): + type: Annotated['PowerOutletTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + power_port: Annotated['PowerPortTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + power_port_id: ID | None = strawberry_django.filter_field() + feed_leg: Annotated['PowerOutletFeedLegEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.PowerPanel, lookups=True) -@autotype_decorator(filtersets.PowerPanelFilterSet) -class PowerPanelFilter(BaseFilterMixin): - pass +class PowerPanelFilter(ContactFilterMixin, ImageAttachmentFilterMixin, PrimaryModelFilterMixin): + site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + site_id: ID | None = strawberry_django.filter_field() + location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.PowerPort, lookups=True) -@autotype_decorator(filtersets.PowerPortFilterSet) -class PowerPortFilter(BaseFilterMixin): - pass +class PowerPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['PowerPortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + maximum_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + allocated_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.PowerPortTemplate, lookups=True) -@autotype_decorator(filtersets.PowerPortTemplateFilterSet) -class PowerPortTemplateFilter(BaseFilterMixin): - pass +class PowerPortTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['PowerPortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + maximum_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + allocated_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.RackType, lookups=True) -@autotype_decorator(filtersets.RackTypeFilterSet) -class RackTypeFilter(BaseFilterMixin): - pass +class RackTypeFilter(RackBaseFilterMixin): + form_factor: Annotated['RackFormFactorEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + manufacturer_id: ID | None = strawberry_django.filter_field() + model: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Rack, lookups=True) -@autotype_decorator(filtersets.RackFilterSet) -class RackFilter(BaseFilterMixin): - pass +class RackFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, RackBaseFilterMixin): + form_factor: Annotated['RackFormFactorEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + rack_type: Annotated['RackTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + rack_type_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + facility_id: FilterLookup[str] | None = strawberry_django.filter_field() + site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + site_id: ID | None = strawberry_django.filter_field() + location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + status: Annotated['RackStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + role: Annotated['RackRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + role_id: ID | None = strawberry_django.filter_field() + serial: FilterLookup[str] | None = strawberry_django.filter_field() + asset_tag: FilterLookup[str] | None = strawberry_django.filter_field() + airflow: Annotated['RackAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.RackReservation, lookups=True) -@autotype_decorator(filtersets.RackReservationFilterSet) -class RackReservationFilter(BaseFilterMixin): - pass +class RackReservationFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + rack_id: ID | None = strawberry_django.filter_field() + units: Annotated['IntegerArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + user_id: ID | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.RackRole, lookups=True) -@autotype_decorator(filtersets.RackRoleFilterSet) -class RackRoleFilter(BaseFilterMixin): - pass +class RackRoleFilter(OrganizationalModelFilterMixin): + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() @strawberry_django.filter(models.RearPort, lookups=True) -@autotype_decorator(filtersets.RearPortFilterSet) -class RearPortFilter(BaseFilterMixin): - pass +class RearPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin): + type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + positions: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.RearPortTemplate, lookups=True) -@autotype_decorator(filtersets.RearPortTemplateFilterSet) -class RearPortTemplateFilter(BaseFilterMixin): - pass +class RearPortTemplateFilter(ModularComponentTemplateFilterMixin): + type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + positions: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Region, lookups=True) -@autotype_decorator(filtersets.RegionFilterSet) -class RegionFilter(BaseFilterMixin): - pass +class RegionFilter(ContactFilterMixin, NestedGroupModelFilterMixin): + prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Site, lookups=True) -@autotype_decorator(filtersets.SiteFilterSet) -class SiteFilter(BaseFilterMixin): - pass +class SiteFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + status: Annotated['SiteStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field() + region: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + region_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + group: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + facility: FilterLookup[str] | None = strawberry_django.filter_field() + asns: Annotated['ASNFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + time_zone: FilterLookup[str] | None = strawberry_django.filter_field() + physical_address: FilterLookup[str] | None = strawberry_django.filter_field() + shipping_address: FilterLookup[str] | None = strawberry_django.filter_field() + latitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + longitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.SiteGroup, lookups=True) -@autotype_decorator(filtersets.SiteGroupFilterSet) -class SiteGroupFilter(BaseFilterMixin): - pass +class SiteGroupFilter(ContactFilterMixin, NestedGroupModelFilterMixin): + prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.VirtualChassis, lookups=True) -@autotype_decorator(filtersets.VirtualChassisFilterSet) -class VirtualChassisFilter(BaseFilterMixin): - pass +class VirtualChassisFilter(PrimaryModelFilterMixin): + master: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + master_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + domain: FilterLookup[str] | None = strawberry_django.filter_field() + member_count: FilterLookup[int] | None = strawberry_django.filter_field() @strawberry_django.filter(models.VirtualDeviceContext, lookups=True) -@autotype_decorator(filtersets.VirtualDeviceContextFilterSet) -class VirtualDeviceContextFilter(BaseFilterMixin): - pass +class VirtualDeviceContextFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + device_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + status: Annotated['VirtualDeviceContextStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + identifier: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + primary_ip4: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + primary_ip4_id: ID | None = strawberry_django.filter_field() + primary_ip6: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + primary_ip6_id: ID | None = strawberry_django.filter_field() + comments: FilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/dcim/graphql/schema.py b/netbox/dcim/graphql/schema.py index 011a2b58b69..1b0661bc2c6 100644 --- a/netbox/dcim/graphql/schema.py +++ b/netbox/dcim/graphql/schema.py @@ -77,6 +77,9 @@ class DCIMQuery: module_bay_template: ModuleBayTemplateType = strawberry_django.field() module_bay_template_list: List[ModuleBayTemplateType] = strawberry_django.field() + module_type_profile: ModuleTypeProfileType = strawberry_django.field() + module_type_profile_list: List[ModuleTypeProfileType] = strawberry_django.field() + module_type: ModuleTypeType = strawberry_django.field() module_type_list: List[ModuleTypeType] = strawberry_django.field() diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index 8d992176a22..fb8c136ad63 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -1,4 +1,4 @@ -from typing import Annotated, List, Union +from typing import Annotated, List, TYPE_CHECKING, Union import strawberry import strawberry_django @@ -6,7 +6,11 @@ import strawberry_django from core.graphql.mixins import ChangelogMixin from dcim import models from extras.graphql.mixins import ( - ConfigContextMixin, ContactsMixin, CustomFieldsMixin, ImageAttachmentsMixin, TagsMixin, + ConfigContextMixin, + ContactsMixin, + CustomFieldsMixin, + ImageAttachmentsMixin, + TagsMixin, ) from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin from netbox.graphql.scalars import BigInt @@ -14,6 +18,23 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, Organizationa from .filters import * from .mixins import CabledObjectMixin, PathEndpointMixin +if TYPE_CHECKING: + from circuits.graphql.types import CircuitTerminationType + from extras.graphql.types import ConfigTemplateType + from ipam.graphql.types import ( + ASNType, + IPAddressType, + PrefixType, + ServiceType, + VLANTranslationPolicyType, + VLANType, + VRFType, + ) + from tenancy.graphql.types import TenantType + from users.graphql.types import UserType + from virtualization.graphql.types import ClusterType, VMInterfaceType, VirtualMachineType + from wireless.graphql.types import WirelessLANType, WirelessLinkType + __all__ = ( 'CableType', 'ComponentType', @@ -40,6 +61,7 @@ __all__ = ( 'ModuleType', 'ModuleBayType', 'ModuleBayTemplateType', + 'ModuleTypeProfileType', 'ModuleTypeType', 'PlatformType', 'PowerFeedType', @@ -111,8 +133,9 @@ class ModularComponentTemplateType(ComponentTemplateType): @strawberry_django.type( models.CableTermination, - exclude=('termination_type', 'termination_id', '_device', '_rack', '_location', '_site'), - filters=CableTerminationFilter + exclude=['termination_type', 'termination_id', '_device', '_rack', '_location', '_site'], + filters=CableTerminationFilter, + pagination=True ) class CableTerminationType(NetBoxObjectType): cable: Annotated["CableType", strawberry.lazy('dcim.graphql.types')] | None @@ -132,7 +155,8 @@ class CableTerminationType(NetBoxObjectType): @strawberry_django.type( models.Cable, fields='__all__', - filters=CableFilter + filters=CableFilter, + pagination=True ) class CableType(NetBoxObjectType): color: str @@ -167,8 +191,9 @@ class CableType(NetBoxObjectType): @strawberry_django.type( models.ConsolePort, - exclude=('_path',), - filters=ConsolePortFilter + exclude=['_path'], + filters=ConsolePortFilter, + pagination=True ) class ConsolePortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): pass @@ -177,7 +202,8 @@ class ConsolePortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin @strawberry_django.type( models.ConsolePortTemplate, fields='__all__', - filters=ConsolePortTemplateFilter + filters=ConsolePortTemplateFilter, + pagination=True ) class ConsolePortTemplateType(ModularComponentTemplateType): pass @@ -185,8 +211,9 @@ class ConsolePortTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.ConsoleServerPort, - exclude=('_path',), - filters=ConsoleServerPortFilter + exclude=['_path'], + filters=ConsoleServerPortFilter, + pagination=True ) class ConsoleServerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): pass @@ -195,7 +222,8 @@ class ConsoleServerPortType(ModularComponentType, CabledObjectMixin, PathEndpoin @strawberry_django.type( models.ConsoleServerPortTemplate, fields='__all__', - filters=ConsoleServerPortTemplateFilter + filters=ConsoleServerPortTemplateFilter, + pagination=True ) class ConsoleServerPortTemplateType(ModularComponentTemplateType): pass @@ -204,7 +232,8 @@ class ConsoleServerPortTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.Device, fields='__all__', - filters=DeviceFilter + filters=DeviceFilter, + pagination=True ) class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): console_port_count: BigInt @@ -259,7 +288,8 @@ class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, NetBo @strawberry_django.type( models.DeviceBay, fields='__all__', - filters=DeviceBayFilter + filters=DeviceBayFilter, + pagination=True ) class DeviceBayType(ComponentType): installed_device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None @@ -268,7 +298,8 @@ class DeviceBayType(ComponentType): @strawberry_django.type( models.DeviceBayTemplate, fields='__all__', - filters=DeviceBayTemplateFilter + filters=DeviceBayTemplateFilter, + pagination=True ) class DeviceBayTemplateType(ComponentTemplateType): pass @@ -276,8 +307,9 @@ class DeviceBayTemplateType(ComponentTemplateType): @strawberry_django.type( models.InventoryItemTemplate, - exclude=('component_type', 'component_id', 'parent'), - filters=InventoryItemTemplateFilter + exclude=['component_type', 'component_id', 'parent'], + filters=InventoryItemTemplateFilter, + pagination=True ) class InventoryItemTemplateType(ComponentTemplateType): role: Annotated["InventoryItemRoleType", strawberry.lazy('dcim.graphql.types')] | None @@ -303,9 +335,12 @@ class InventoryItemTemplateType(ComponentTemplateType): @strawberry_django.type( models.DeviceRole, fields='__all__', - filters=DeviceRoleFilter + filters=DeviceRoleFilter, + pagination=True ) class DeviceRoleType(OrganizationalObjectType): + parent: Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')] | None + children: List[Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')]] color: str config_template: Annotated["ConfigTemplateType", strawberry.lazy('extras.graphql.types')] | None @@ -316,7 +351,8 @@ class DeviceRoleType(OrganizationalObjectType): @strawberry_django.type( models.DeviceType, fields='__all__', - filters=DeviceTypeFilter + filters=DeviceTypeFilter, + pagination=True ) class DeviceTypeType(NetBoxObjectType): console_port_template_count: BigInt @@ -350,7 +386,8 @@ class DeviceTypeType(NetBoxObjectType): @strawberry_django.type( models.FrontPort, fields='__all__', - filters=FrontPortFilter + filters=FrontPortFilter, + pagination=True ) class FrontPortType(ModularComponentType, CabledObjectMixin): color: str @@ -360,7 +397,8 @@ class FrontPortType(ModularComponentType, CabledObjectMixin): @strawberry_django.type( models.FrontPortTemplate, fields='__all__', - filters=FrontPortTemplateFilter + filters=FrontPortTemplateFilter, + pagination=True ) class FrontPortTemplateType(ModularComponentTemplateType): color: str @@ -369,8 +407,9 @@ class FrontPortTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.MACAddress, - exclude=('assigned_object_type', 'assigned_object_id'), - filters=MACAddressFilter + exclude=['assigned_object_type', 'assigned_object_id'], + filters=MACAddressFilter, + pagination=True ) class MACAddressType(NetBoxObjectType): mac_address: str @@ -385,8 +424,9 @@ class MACAddressType(NetBoxObjectType): @strawberry_django.type( models.Interface, - exclude=('_path',), - filters=InterfaceFilter + exclude=['_path'], + filters=InterfaceFilter, + pagination=True ) class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin): _name: str @@ -413,7 +453,8 @@ class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, P @strawberry_django.type( models.InterfaceTemplate, fields='__all__', - filters=InterfaceTemplateFilter + filters=InterfaceTemplateFilter, + pagination=True ) class InterfaceTemplateType(ModularComponentTemplateType): _name: str @@ -424,8 +465,9 @@ class InterfaceTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.InventoryItem, - exclude=('component_type', 'component_id', 'parent'), - filters=InventoryItemFilter + exclude=['component_type', 'component_id', 'parent'], + filters=InventoryItemFilter, + pagination=True ) class InventoryItemType(ComponentType): role: Annotated["InventoryItemRoleType", strawberry.lazy('dcim.graphql.types')] | None @@ -451,7 +493,8 @@ class InventoryItemType(ComponentType): @strawberry_django.type( models.InventoryItemRole, fields='__all__', - filters=InventoryItemRoleFilter + filters=InventoryItemRoleFilter, + pagination=True ) class InventoryItemRoleType(OrganizationalObjectType): color: str @@ -463,8 +506,9 @@ class InventoryItemRoleType(OrganizationalObjectType): @strawberry_django.type( models.Location, # fields='__all__', - exclude=('parent',), # bug - temp - filters=LocationFilter + exclude=['parent'], # bug - temp + filters=LocationFilter, + pagination=True ) class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, OrganizationalObjectType): site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] @@ -491,7 +535,8 @@ class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, Organi @strawberry_django.type( models.Manufacturer, fields='__all__', - filters=ManufacturerFilter + filters=ManufacturerFilter, + pagination=True ) class ManufacturerType(OrganizationalObjectType, ContactsMixin): @@ -505,7 +550,8 @@ class ManufacturerType(OrganizationalObjectType, ContactsMixin): @strawberry_django.type( models.Module, fields='__all__', - filters=ModuleFilter + filters=ModuleFilter, + pagination=True ) class ModuleType(NetBoxObjectType): device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] @@ -524,8 +570,9 @@ class ModuleType(NetBoxObjectType): @strawberry_django.type( models.ModuleBay, # fields='__all__', - exclude=('parent',), - filters=ModuleBayFilter + exclude=['parent'], + filters=ModuleBayFilter, + pagination=True ) class ModuleBayType(ModularComponentType): @@ -540,18 +587,31 @@ class ModuleBayType(ModularComponentType): @strawberry_django.type( models.ModuleBayTemplate, fields='__all__', - filters=ModuleBayTemplateFilter + filters=ModuleBayTemplateFilter, + pagination=True ) class ModuleBayTemplateType(ModularComponentTemplateType): pass +@strawberry_django.type( + models.ModuleTypeProfile, + fields='__all__', + filters=ModuleTypeProfileFilter, + pagination=True +) +class ModuleTypeProfileType(NetBoxObjectType): + module_types: List[Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')]] + + @strawberry_django.type( models.ModuleType, fields='__all__', - filters=ModuleTypeFilter + filters=ModuleTypeFilter, + pagination=True ) class ModuleTypeType(NetBoxObjectType): + profile: Annotated["ModuleTypeProfileType", strawberry.lazy('dcim.graphql.types')] | None manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] frontporttemplates: List[Annotated["FrontPortTemplateType", strawberry.lazy('dcim.graphql.types')]] @@ -567,7 +627,8 @@ class ModuleTypeType(NetBoxObjectType): @strawberry_django.type( models.Platform, fields='__all__', - filters=PlatformFilter + filters=PlatformFilter, + pagination=True ) class PlatformType(OrganizationalObjectType): manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] | None @@ -579,8 +640,9 @@ class PlatformType(OrganizationalObjectType): @strawberry_django.type( models.PowerFeed, - exclude=('_path',), - filters=PowerFeedFilter + exclude=['_path'], + filters=PowerFeedFilter, + pagination=True ) class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin): power_panel: Annotated["PowerPanelType", strawberry.lazy('dcim.graphql.types')] @@ -590,8 +652,9 @@ class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin): @strawberry_django.type( models.PowerOutlet, - exclude=('_path',), - filters=PowerOutletFilter + exclude=['_path'], + filters=PowerOutletFilter, + pagination=True ) class PowerOutletType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): power_port: Annotated["PowerPortType", strawberry.lazy('dcim.graphql.types')] | None @@ -601,7 +664,8 @@ class PowerOutletType(ModularComponentType, CabledObjectMixin, PathEndpointMixin @strawberry_django.type( models.PowerOutletTemplate, fields='__all__', - filters=PowerOutletTemplateFilter + filters=PowerOutletTemplateFilter, + pagination=True ) class PowerOutletTemplateType(ModularComponentTemplateType): power_port: Annotated["PowerPortTemplateType", strawberry.lazy('dcim.graphql.types')] | None @@ -610,7 +674,8 @@ class PowerOutletTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.PowerPanel, fields='__all__', - filters=PowerPanelFilter + filters=PowerPanelFilter, + pagination=True ) class PowerPanelType(NetBoxObjectType, ContactsMixin): site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] @@ -621,8 +686,9 @@ class PowerPanelType(NetBoxObjectType, ContactsMixin): @strawberry_django.type( models.PowerPort, - exclude=('_path',), - filters=PowerPortFilter + exclude=['_path'], + filters=PowerPortFilter, + pagination=True ) class PowerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): @@ -632,7 +698,8 @@ class PowerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): @strawberry_django.type( models.PowerPortTemplate, fields='__all__', - filters=PowerPortTemplateFilter + filters=PowerPortTemplateFilter, + pagination=True ) class PowerPortTemplateType(ModularComponentTemplateType): poweroutlet_templates: List[Annotated["PowerOutletTemplateType", strawberry.lazy('dcim.graphql.types')]] @@ -641,7 +708,8 @@ class PowerPortTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.RackType, fields='__all__', - filters=RackTypeFilter + filters=RackTypeFilter, + pagination=True ) class RackTypeType(NetBoxObjectType): manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] @@ -650,7 +718,8 @@ class RackTypeType(NetBoxObjectType): @strawberry_django.type( models.Rack, fields='__all__', - filters=RackFilter + filters=RackFilter, + pagination=True ) class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] @@ -668,7 +737,8 @@ class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje @strawberry_django.type( models.RackReservation, fields='__all__', - filters=RackReservationFilter + filters=RackReservationFilter, + pagination=True ) class RackReservationType(NetBoxObjectType): units: List[int] @@ -680,7 +750,8 @@ class RackReservationType(NetBoxObjectType): @strawberry_django.type( models.RackRole, fields='__all__', - filters=RackRoleFilter + filters=RackRoleFilter, + pagination=True ) class RackRoleType(OrganizationalObjectType): color: str @@ -691,7 +762,8 @@ class RackRoleType(OrganizationalObjectType): @strawberry_django.type( models.RearPort, fields='__all__', - filters=RearPortFilter + filters=RearPortFilter, + pagination=True ) class RearPortType(ModularComponentType, CabledObjectMixin): color: str @@ -702,7 +774,8 @@ class RearPortType(ModularComponentType, CabledObjectMixin): @strawberry_django.type( models.RearPortTemplate, fields='__all__', - filters=RearPortTemplateFilter + filters=RearPortTemplateFilter, + pagination=True ) class RearPortTemplateType(ModularComponentTemplateType): color: str @@ -712,9 +785,9 @@ class RearPortTemplateType(ModularComponentTemplateType): @strawberry_django.type( models.Region, - exclude=('parent',), - # fields='__all__', - filters=RegionFilter + exclude=['parent'], + filters=RegionFilter, + pagination=True ) class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @@ -739,7 +812,8 @@ class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @strawberry_django.type( models.Site, fields='__all__', - filters=SiteFilter + filters=SiteFilter, + pagination=True ) class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): time_zone: str | None @@ -772,9 +846,9 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje @strawberry_django.type( models.SiteGroup, - # fields='__all__', - exclude=('parent',), # bug - temp - filters=SiteGroupFilter + exclude=['parent'], # bug - temp + filters=SiteGroupFilter, + pagination=True ) class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @@ -799,7 +873,8 @@ class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @strawberry_django.type( models.VirtualChassis, fields='__all__', - filters=VirtualChassisFilter + filters=VirtualChassisFilter, + pagination=True ) class VirtualChassisType(NetBoxObjectType): member_count: BigInt @@ -811,7 +886,8 @@ class VirtualChassisType(NetBoxObjectType): @strawberry_django.type( models.VirtualDeviceContext, fields='__all__', - filters=VirtualDeviceContextFilter + filters=VirtualDeviceContextFilter, + pagination=True ) class VirtualDeviceContextType(NetBoxObjectType): device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None diff --git a/netbox/dcim/migrations/0002_squashed.py b/netbox/dcim/migrations/0002_squashed.py index 2e830560f98..ae1966e58a0 100644 --- a/netbox/dcim/migrations/0002_squashed.py +++ b/netbox/dcim/migrations/0002_squashed.py @@ -7,11 +7,11 @@ import taggit.managers class Migration(migrations.Migration): dependencies = [ - ('dcim', '0001_initial'), + ('dcim', '0001_squashed'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('contenttypes', '0002_remove_content_type_name'), - ('extras', '0001_initial'), - ('tenancy', '0001_initial'), + ('extras', '0001_squashed'), + ('tenancy', '0001_squashed_0012'), ] replaces = [ diff --git a/netbox/dcim/migrations/0003_squashed_0130.py b/netbox/dcim/migrations/0003_squashed_0130.py index 0248d9ba1e3..490ab8e8b95 100644 --- a/netbox/dcim/migrations/0003_squashed_0130.py +++ b/netbox/dcim/migrations/0003_squashed_0130.py @@ -5,12 +5,12 @@ import taggit.managers class Migration(migrations.Migration): dependencies = [ - ('dcim', '0002_auto_20160622_1821'), - ('virtualization', '0001_virtualization'), + ('dcim', '0002_squashed'), + ('virtualization', '0001_squashed_0022'), ('contenttypes', '0002_remove_content_type_name'), - ('ipam', '0001_initial'), - ('tenancy', '0001_initial'), - ('extras', '0002_custom_fields'), + ('ipam', '0001_squashed'), + ('tenancy', '0001_squashed_0012'), + ('extras', '0002_squashed_0059'), ] replaces = [ @@ -505,28 +505,6 @@ class Migration(migrations.Migration): model_name='cable', name='termination_a_type', field=models.ForeignKey( - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), - models.Q( - ('app_label', 'dcim'), - ( - 'model__in', - ( - 'consoleport', - 'consoleserverport', - 'frontport', - 'interface', - 'powerfeed', - 'poweroutlet', - 'powerport', - 'rearport', - ), - ), - ), - _connector='OR', - ) - ), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype', @@ -536,28 +514,6 @@ class Migration(migrations.Migration): model_name='cable', name='termination_b_type', field=models.ForeignKey( - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), - models.Q( - ('app_label', 'dcim'), - ( - 'model__in', - ( - 'consoleport', - 'consoleserverport', - 'frontport', - 'interface', - 'powerfeed', - 'poweroutlet', - 'powerport', - 'rearport', - ), - ), - ), - _connector='OR', - ) - ), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype', diff --git a/netbox/dcim/migrations/0131_squashed_0159.py b/netbox/dcim/migrations/0131_squashed_0159.py index 3866e8cc80b..1c1f2ff381e 100644 --- a/netbox/dcim/migrations/0131_squashed_0159.py +++ b/netbox/dcim/migrations/0131_squashed_0159.py @@ -43,12 +43,12 @@ class Migration(migrations.Migration): ] dependencies = [ - ('tenancy', '0012_standardize_models'), + ('tenancy', '0001_squashed_0012'), ('extras', '0002_squashed_0059'), - ('dcim', '0130_sitegroup'), + ('dcim', '0003_squashed_0130'), ('contenttypes', '0002_remove_content_type_name'), - ('ipam', '0053_asn_model'), - ('wireless', '0001_wireless'), + ('ipam', '0047_squashed_0053'), + ('wireless', '0001_squashed_0008'), ] operations = [ @@ -866,21 +866,6 @@ class Migration(migrations.Migration): name='component_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q( - ('app_label', 'dcim'), - ( - 'model__in', - ( - 'consoleport', - 'consoleserverport', - 'frontport', - 'interface', - 'poweroutlet', - 'powerport', - 'rearport', - ), - ), - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', @@ -1238,21 +1223,6 @@ class Migration(migrations.Migration): 'component_type', models.ForeignKey( blank=True, - limit_choices_to=models.Q( - ('app_label', 'dcim'), - ( - 'model__in', - ( - 'consoleporttemplate', - 'consoleserverporttemplate', - 'frontporttemplate', - 'interfacetemplate', - 'poweroutlettemplate', - 'powerporttemplate', - 'rearporttemplate', - ), - ), - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', @@ -1478,28 +1448,6 @@ class Migration(migrations.Migration): ( 'termination_type', models.ForeignKey( - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), - models.Q( - ('app_label', 'dcim'), - ( - 'model__in', - ( - 'consoleport', - 'consoleserverport', - 'frontport', - 'interface', - 'powerfeed', - 'poweroutlet', - 'powerport', - 'rearport', - ), - ), - ), - _connector='OR', - ) - ), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype', diff --git a/netbox/dcim/migrations/0160_squashed_0166.py b/netbox/dcim/migrations/0160_squashed_0166.py index 0deb58bab3f..5cff94f4a28 100644 --- a/netbox/dcim/migrations/0160_squashed_0166.py +++ b/netbox/dcim/migrations/0160_squashed_0166.py @@ -18,9 +18,9 @@ class Migration(migrations.Migration): dependencies = [ ('ipam', '0047_squashed_0053'), - ('tenancy', '0009_standardize_description_comments'), - ('circuits', '0037_new_cabling_models'), - ('dcim', '0159_populate_cable_paths'), + ('tenancy', '0001_squashed_0012'), + ('circuits', '0003_squashed_0037'), + ('dcim', '0131_squashed_0159'), ] operations = [ diff --git a/netbox/dcim/migrations/0167_squashed_0182.py b/netbox/dcim/migrations/0167_squashed_0182.py index d0ad5379ff1..ba077ff4e56 100644 --- a/netbox/dcim/migrations/0167_squashed_0182.py +++ b/netbox/dcim/migrations/0167_squashed_0182.py @@ -27,10 +27,10 @@ class Migration(migrations.Migration): ] dependencies = [ - ('extras', '0086_configtemplate'), - ('tenancy', '0010_tenant_relax_uniqueness'), + ('extras', '0060_squashed_0086'), + ('tenancy', '0002_squashed_0011'), ('ipam', '0047_squashed_0053'), - ('dcim', '0166_virtualdevicecontext'), + ('dcim', '0160_squashed_0166'), ] operations = [ diff --git a/netbox/dcim/migrations/0183_devicetype_exclude_from_utilization.py b/netbox/dcim/migrations/0183_devicetype_exclude_from_utilization.py index f9f2c20b4fd..2e3edb08ad7 100644 --- a/netbox/dcim/migrations/0183_devicetype_exclude_from_utilization.py +++ b/netbox/dcim/migrations/0183_devicetype_exclude_from_utilization.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('dcim', '0182_zero_length_cable_fix'), + ('dcim', '0167_squashed_0182'), ] operations = [ diff --git a/netbox/dcim/migrations/0199_macaddress.py b/netbox/dcim/migrations/0199_macaddress.py index ae18d5f6330..c668858b43b 100644 --- a/netbox/dcim/migrations/0199_macaddress.py +++ b/netbox/dcim/migrations/0199_macaddress.py @@ -31,13 +31,6 @@ class Migration(migrations.Migration): 'assigned_object_type', models.ForeignKey( blank=True, - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'dcim'), ('model', 'interface')), - models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), - _connector='OR', - ) - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', diff --git a/netbox/dcim/migrations/0201_add_power_outlet_status.py b/netbox/dcim/migrations/0201_add_power_outlet_status.py new file mode 100644 index 00000000000..21fd3218641 --- /dev/null +++ b/netbox/dcim/migrations/0201_add_power_outlet_status.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0200_populate_mac_addresses'), + ] + + operations = [ + migrations.AddField( + model_name='poweroutlet', + name='status', + field=models.CharField(default='enabled', max_length=50), + ), + ] diff --git a/netbox/dcim/migrations/0202_location_comments_region_comments_sitegroup_comments.py b/netbox/dcim/migrations/0202_location_comments_region_comments_sitegroup_comments.py new file mode 100644 index 00000000000..ffdc5ba8a55 --- /dev/null +++ b/netbox/dcim/migrations/0202_location_comments_region_comments_sitegroup_comments.py @@ -0,0 +1,26 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0201_add_power_outlet_status'), + ] + + operations = [ + migrations.AddField( + model_name='location', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='region', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='sitegroup', + name='comments', + field=models.TextField(blank=True), + ), + ] diff --git a/netbox/dcim/migrations/0203_add_rack_outer_height.py b/netbox/dcim/migrations/0203_add_rack_outer_height.py new file mode 100644 index 00000000000..2d2fef265de --- /dev/null +++ b/netbox/dcim/migrations/0203_add_rack_outer_height.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2b1 on 2025-03-18 15:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0202_location_comments_region_comments_sitegroup_comments'), + ] + + operations = [ + migrations.AddField( + model_name='rack', + name='outer_height', + field=models.PositiveSmallIntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name='racktype', + name='outer_height', + field=models.PositiveSmallIntegerField(blank=True, null=True), + ), + ] diff --git a/netbox/dcim/migrations/0203_device_role_nested.py b/netbox/dcim/migrations/0203_device_role_nested.py new file mode 100644 index 00000000000..c9dd791b3a0 --- /dev/null +++ b/netbox/dcim/migrations/0203_device_role_nested.py @@ -0,0 +1,65 @@ +# Generated by Django 5.1.7 on 2025-03-25 18:06 + +import django.db.models.manager +import mptt.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0203_add_rack_outer_height'), + ] + + operations = [ + migrations.AddField( + model_name='devicerole', + name='level', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='devicerole', + name='lft', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='devicerole', + name='rght', + field=models.PositiveIntegerField(default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='devicerole', + name='tree_id', + field=models.PositiveIntegerField(db_index=True, default=0, editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='devicerole', + name='parent', + field=mptt.fields.TreeForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='children', + to='dcim.devicerole', + ), + ), + migrations.AddField( + model_name='devicerole', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AlterField( + model_name='devicerole', + name='name', + field=models.CharField(max_length=100), + ), + migrations.AlterField( + model_name='devicerole', + name='slug', + field=models.SlugField(max_length=100), + ), + ] diff --git a/netbox/dcim/migrations/0204_device_role_rebuild.py b/netbox/dcim/migrations/0204_device_role_rebuild.py new file mode 100644 index 00000000000..69837c52203 --- /dev/null +++ b/netbox/dcim/migrations/0204_device_role_rebuild.py @@ -0,0 +1,22 @@ +from django.db import migrations +import mptt +import mptt.managers + + +def rebuild_mptt(apps, schema_editor): + manager = mptt.managers.TreeManager() + DeviceRole = apps.get_model('dcim', 'DeviceRole') + manager.model = DeviceRole + mptt.register(DeviceRole) + manager.contribute_to_class(DeviceRole, 'objects') + manager.rebuild() + + +class Migration(migrations.Migration): + dependencies = [ + ('dcim', '0203_device_role_nested'), + ] + + operations = [ + migrations.RunPython(code=rebuild_mptt, reverse_code=migrations.RunPython.noop), + ] diff --git a/netbox/dcim/migrations/0205_moduletypeprofile.py b/netbox/dcim/migrations/0205_moduletypeprofile.py new file mode 100644 index 00000000000..3e9a4d6d85e --- /dev/null +++ b/netbox/dcim/migrations/0205_moduletypeprofile.py @@ -0,0 +1,57 @@ +import django.db.models.deletion +import taggit.managers +from django.db import migrations, models + +import utilities.json + + +class Migration(migrations.Migration): + dependencies = [ + ('dcim', '0204_device_role_rebuild'), + ('extras', '0125_exporttemplate_file_name'), + ] + + operations = [ + migrations.CreateModel( + name='ModuleTypeProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), + ('description', models.CharField(blank=True, max_length=200)), + ('comments', models.TextField(blank=True)), + ('name', models.CharField(max_length=100, unique=True)), + ('schema', models.JSONField(blank=True, null=True)), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={ + 'verbose_name': 'module type profile', + 'verbose_name_plural': 'module type profiles', + 'ordering': ('name',), + }, + ), + migrations.AddField( + model_name='moduletype', + name='attribute_data', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='moduletype', + name='profile', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='module_types', + to='dcim.moduletypeprofile', + ), + ), + migrations.AlterModelOptions( + name='moduletype', + options={'ordering': ('profile', 'manufacturer', 'model')}, + ), + ] diff --git a/netbox/dcim/migrations/0206_load_module_type_profiles.py b/netbox/dcim/migrations/0206_load_module_type_profiles.py new file mode 100644 index 00000000000..e3ca7d27adc --- /dev/null +++ b/netbox/dcim/migrations/0206_load_module_type_profiles.py @@ -0,0 +1,42 @@ +import json +from pathlib import Path + +from django.db import migrations + +DATA_FILES_PATH = Path(__file__).parent / 'initial_data' / 'module_type_profiles' + + +def load_initial_data(apps, schema_editor): + """ + Load initial ModuleTypeProfile objects from file. + """ + ModuleTypeProfile = apps.get_model('dcim', 'ModuleTypeProfile') + initial_profiles = ( + 'cpu', + 'fan', + 'gpu', + 'hard_disk', + 'memory', + 'power_supply' + ) + + for name in initial_profiles: + file_path = DATA_FILES_PATH / f'{name}.json' + with file_path.open('r') as f: + data = json.load(f) + try: + ModuleTypeProfile.objects.create(**data) + except Exception as e: + print(f"Error loading data from {file_path}") + raise e + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0205_moduletypeprofile'), + ] + + operations = [ + migrations.RunPython(load_initial_data), + ] diff --git a/netbox/dcim/migrations/0207_remove_redundant_indexes.py b/netbox/dcim/migrations/0207_remove_redundant_indexes.py new file mode 100644 index 00000000000..b63e6423fef --- /dev/null +++ b/netbox/dcim/migrations/0207_remove_redundant_indexes.py @@ -0,0 +1,17 @@ +# Generated by Django 5.2b1 on 2025-04-03 18:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0206_load_module_type_profiles'), + ] + + operations = [ + migrations.RemoveIndex( + model_name='cabletermination', + name='dcim_cablet_termina_884752_idx', + ), + ] diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/cpu.json b/netbox/dcim/migrations/initial_data/module_type_profiles/cpu.json new file mode 100644 index 00000000000..255886c5e3f --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/cpu.json @@ -0,0 +1,20 @@ +{ + "name": "CPU", + "schema": { + "properties": { + "architecture": { + "type": "string", + "title": "Architecture" + }, + "speed": { + "type": "number", + "title": "Speed", + "description": "Clock speed in GHz" + }, + "cores": { + "type": "integer", + "description": "Number of cores present" + } + } + } +} diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/fan.json b/netbox/dcim/migrations/initial_data/module_type_profiles/fan.json new file mode 100644 index 00000000000..e6a2a384e3c --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/fan.json @@ -0,0 +1,12 @@ +{ + "name": "Fan", + "schema": { + "properties": { + "rpm": { + "type": "integer", + "title": "RPM", + "description": "Fan speed (RPM)" + } + } + } +} diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/gpu.json b/netbox/dcim/migrations/initial_data/module_type_profiles/gpu.json new file mode 100644 index 00000000000..1725a4ab708 --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/gpu.json @@ -0,0 +1,28 @@ +{ + "name": "GPU", + "schema": { + "properties": { + "interface": { + "type": "string", + "enum": [ + "PCIe 4.0", + "PCIe 4.0 x8", + "PCIe 4.0 x16", + "PCIe 5.0 x16" + ] + }, + "gpu" : { + "type": "string", + "title": "GPU" + }, + "memory": { + "type": "integer", + "title": "Memory (GB)", + "description": "Total memory capacity (in GB)" + } + }, + "required": [ + "memory" + ] + } +} diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/hard_disk.json b/netbox/dcim/migrations/initial_data/module_type_profiles/hard_disk.json new file mode 100644 index 00000000000..8d55cfde632 --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/hard_disk.json @@ -0,0 +1,29 @@ +{ + "name": "Hard disk", + "schema": { + "properties": { + "type": { + "type": "string", + "title": "Disk type", + "enum": [ + "HD", + "SSD", + "NVME" + ], + "default": "SSD" + }, + "size": { + "type": "integer", + "title": "Size (GB)", + "description": "Raw disk capacity" + }, + "speed": { + "type": "integer", + "title": "Speed (RPM)" + } + }, + "required": [ + "size" + ] + } +} diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/memory.json b/netbox/dcim/migrations/initial_data/module_type_profiles/memory.json new file mode 100644 index 00000000000..8346bfce992 --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/memory.json @@ -0,0 +1,36 @@ +{ + "name": "Memory", + "schema": { + "properties": { + "class": { + "type": "string", + "title": "Memory class", + "enum": [ + "DDR3", + "DDR4", + "DDR5" + ], + "default": "DDR5" + }, + "size": { + "type": "integer", + "title": "Size (GB)", + "description": "Raw capacity of the module" + }, + "data_rate": { + "type": "integer", + "title": "Data rate", + "description": "Speed in MT/s" + }, + "ecc": { + "type": "boolean", + "title": "ECC", + "description": "Error-correcting code is enabled" + } + }, + "required": [ + "class", + "size" + ] + } +} diff --git a/netbox/dcim/migrations/initial_data/module_type_profiles/power_supply.json b/netbox/dcim/migrations/initial_data/module_type_profiles/power_supply.json new file mode 100644 index 00000000000..ea060a88909 --- /dev/null +++ b/netbox/dcim/migrations/initial_data/module_type_profiles/power_supply.json @@ -0,0 +1,34 @@ +{ + "name": "Power supply", + "schema": { + "properties": { + "input_current": { + "type": "string", + "title": "Current type", + "enum": [ + "AC", + "DC" + ], + "default": "AC" + }, + "input_voltage": { + "type": "integer", + "title": "Voltage", + "default": 120 + }, + "wattage": { + "type": "integer", + "description": "Available output power (watts)" + }, + "hot_swappable": { + "type": "boolean", + "title": "Hot-swappable", + "default": false + } + }, + "required": [ + "input_current", + "input_voltage" + ] + } +} diff --git a/netbox/dcim/models/__init__.py b/netbox/dcim/models/__init__.py index d74f3482888..33af25678f1 100644 --- a/netbox/dcim/models/__init__.py +++ b/netbox/dcim/models/__init__.py @@ -2,6 +2,7 @@ from .cables import * from .device_component_templates import * from .device_components import * from .devices import * +from .modules import * from .power import * from .racks import * from .sites import * diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index 7117ea7e001..edb010a2219 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -259,7 +259,6 @@ class CableTermination(ChangeLoggedModel): ) termination_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=CABLE_TERMINATION_MODELS, on_delete=models.PROTECT, related_name='+' ) @@ -299,9 +298,6 @@ class CableTermination(ChangeLoggedModel): class Meta: ordering = ('cable', 'cable_end', 'pk') - indexes = ( - models.Index(fields=('termination_type', 'termination_id')), - ) constraints = ( models.UniqueConstraint( fields=('termination_type', 'termination_id'), diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index b4f0577119b..e0b05b388a2 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -751,7 +751,6 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): ) component_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=MODULAR_COMPONENT_TEMPLATE_MODELS, on_delete=models.PROTECT, related_name='+', blank=True, diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index ce9e5607f89..0ff74529f87 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -449,6 +449,12 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint, Tracki """ A physical power outlet (output) within a Device which provides power to a PowerPort. """ + status = models.CharField( + verbose_name=_('status'), + max_length=50, + choices=PowerOutletStatusChoices, + default=PowerOutletStatusChoices.STATUS_ENABLED + ) type = models.CharField( verbose_name=_('type'), max_length=50, @@ -492,6 +498,9 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint, Tracki _("Parent power port ({power_port}) must belong to the same device").format(power_port=self.power_port) ) + def get_status_color(self): + return PowerOutletStatusChoices.colors.get(self.status) + # # Interfaces @@ -934,6 +943,8 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd raise ValidationError({'rf_channel_width': _("Cannot specify custom width with channel selected.")}) # VLAN validation + if not self.mode and self.untagged_vlan: + raise ValidationError({'untagged_vlan': _("Interface mode does not support an untagged vlan.")}) # Validate untagged VLAN if self.untagged_vlan and self.untagged_vlan.site not in [self.device.site, None]: @@ -1263,7 +1274,6 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin): ) component_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=MODULAR_COMPONENT_MODELS, on_delete=models.PROTECT, related_name='+', blank=True, diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 2acd98801b1..f9c72b7c63f 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -19,17 +19,19 @@ from core.models import ObjectType from dcim.choices import * from dcim.constants import * from dcim.fields import MACAddressField +from dcim.utils import update_interface_bridges from extras.models import ConfigContextModel, CustomField from extras.querysets import ConfigContextModelQuerySet from netbox.choices import ColorChoices from netbox.config import ConfigItem -from netbox.models import OrganizationalModel, PrimaryModel +from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel from netbox.models.mixins import WeightMixin from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from utilities.fields import ColorField, CounterCacheField from utilities.tracking import TrackingModelMixin from .device_components import * from .mixins import RenderConfigMixin +from .modules import Module __all__ = ( @@ -38,8 +40,6 @@ __all__ = ( 'DeviceType', 'MACAddress', 'Manufacturer', - 'Module', - 'ModuleType', 'Platform', 'VirtualChassis', 'VirtualDeviceContext', @@ -367,108 +367,11 @@ class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): return self.subdevice_role == SubdeviceRoleChoices.ROLE_CHILD -class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): - """ - A ModuleType represents a hardware element that can be installed within a device and which houses additional - components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a - DeviceType, each ModuleType can have console, power, interface, and pass-through port templates assigned to it. It - cannot, however house device bays or module bays. - """ - manufacturer = models.ForeignKey( - to='dcim.Manufacturer', - on_delete=models.PROTECT, - related_name='module_types' - ) - model = models.CharField( - verbose_name=_('model'), - max_length=100 - ) - part_number = models.CharField( - verbose_name=_('part number'), - max_length=50, - blank=True, - help_text=_('Discrete part number (optional)') - ) - airflow = models.CharField( - verbose_name=_('airflow'), - max_length=50, - choices=ModuleAirflowChoices, - blank=True, - null=True - ) - - clone_fields = ('manufacturer', 'weight', 'weight_unit', 'airflow') - prerequisite_models = ( - 'dcim.Manufacturer', - ) - - class Meta: - ordering = ('manufacturer', 'model') - constraints = ( - models.UniqueConstraint( - fields=('manufacturer', 'model'), - name='%(app_label)s_%(class)s_unique_manufacturer_model' - ), - ) - verbose_name = _('module type') - verbose_name_plural = _('module types') - - def __str__(self): - return self.model - - @property - def full_name(self): - return f"{self.manufacturer} {self.model}" - - def to_yaml(self): - data = { - 'manufacturer': self.manufacturer.name, - 'model': self.model, - 'part_number': self.part_number, - 'description': self.description, - 'weight': float(self.weight) if self.weight is not None else None, - 'weight_unit': self.weight_unit, - 'comments': self.comments, - } - - # Component templates - if self.consoleporttemplates.exists(): - data['console-ports'] = [ - c.to_yaml() for c in self.consoleporttemplates.all() - ] - if self.consoleserverporttemplates.exists(): - data['console-server-ports'] = [ - c.to_yaml() for c in self.consoleserverporttemplates.all() - ] - if self.powerporttemplates.exists(): - data['power-ports'] = [ - c.to_yaml() for c in self.powerporttemplates.all() - ] - if self.poweroutlettemplates.exists(): - data['power-outlets'] = [ - c.to_yaml() for c in self.poweroutlettemplates.all() - ] - if self.interfacetemplates.exists(): - data['interfaces'] = [ - c.to_yaml() for c in self.interfacetemplates.all() - ] - if self.frontporttemplates.exists(): - data['front-ports'] = [ - c.to_yaml() for c in self.frontporttemplates.all() - ] - if self.rearporttemplates.exists(): - data['rear-ports'] = [ - c.to_yaml() for c in self.rearporttemplates.all() - ] - - return yaml.dump(dict(data), sort_keys=False) - - # # Devices # -class DeviceRole(OrganizationalModel): +class DeviceRole(NestedGroupModel): """ Devices are organized by functional role; for example, "Core Switch" or "File Server". Each DeviceRole is assigned a color to be used when displaying rack elevations. The vm_role field determines whether the role is applicable to @@ -491,6 +394,8 @@ class DeviceRole(OrganizationalModel): null=True ) + clone_fields = ('parent', 'description') + class Meta: ordering = ('name',) verbose_name = _('device role') @@ -524,23 +429,6 @@ class Platform(OrganizationalModel): verbose_name_plural = _('platforms') -def update_interface_bridges(device, interface_templates, module=None): - """ - Used for device and module instantiation. Iterates all InterfaceTemplates with a bridge assigned - and applies it to the actual interfaces. - """ - for interface_template in interface_templates.exclude(bridge=None): - interface = Interface.objects.get(device=device, name=interface_template.resolve_name(module=module)) - - if interface_template.bridge: - interface.bridge = Interface.objects.get( - device=device, - name=interface_template.bridge.resolve_name(module=module) - ) - interface.full_clean() - interface.save() - - class Device( ContactsMixin, ImageAttachmentsMixin, @@ -1153,170 +1041,6 @@ class Device( return round(total_weight / 1000, 2) -class Module(PrimaryModel, ConfigContextModel): - """ - A Module represents a field-installable component within a Device which may itself hold multiple device components - (for example, a line card within a chassis switch). Modules are instantiated from ModuleTypes. - """ - device = models.ForeignKey( - to='dcim.Device', - on_delete=models.CASCADE, - related_name='modules' - ) - module_bay = models.OneToOneField( - to='dcim.ModuleBay', - on_delete=models.CASCADE, - related_name='installed_module' - ) - module_type = models.ForeignKey( - to='dcim.ModuleType', - on_delete=models.PROTECT, - related_name='instances' - ) - status = models.CharField( - verbose_name=_('status'), - max_length=50, - choices=ModuleStatusChoices, - default=ModuleStatusChoices.STATUS_ACTIVE - ) - serial = models.CharField( - max_length=50, - blank=True, - verbose_name=_('serial number') - ) - asset_tag = models.CharField( - max_length=50, - blank=True, - null=True, - unique=True, - verbose_name=_('asset tag'), - help_text=_('A unique tag used to identify this device') - ) - - clone_fields = ('device', 'module_type', 'status') - - class Meta: - ordering = ('module_bay',) - verbose_name = _('module') - verbose_name_plural = _('modules') - - def __str__(self): - return f'{self.module_bay.name}: {self.module_type} ({self.pk})' - - def get_status_color(self): - return ModuleStatusChoices.colors.get(self.status) - - def clean(self): - super().clean() - - if hasattr(self, "module_bay") and (self.module_bay.device != self.device): - raise ValidationError( - _("Module must be installed within a module bay belonging to the assigned device ({device}).").format( - device=self.device - ) - ) - - # Check for recursion - module = self - module_bays = [] - modules = [] - while module: - if module.pk in modules or module.module_bay.pk in module_bays: - raise ValidationError(_("A module bay cannot belong to a module installed within it.")) - modules.append(module.pk) - module_bays.append(module.module_bay.pk) - module = module.module_bay.module if module.module_bay else None - - def save(self, *args, **kwargs): - is_new = self.pk is None - - super().save(*args, **kwargs) - - adopt_components = getattr(self, '_adopt_components', False) - disable_replication = getattr(self, '_disable_replication', False) - - # We skip adding components if the module is being edited or - # both replication and component adoption is disabled - if not is_new or (disable_replication and not adopt_components): - return - - # Iterate all component types - for templates, component_attribute, component_model in [ - ("consoleporttemplates", "consoleports", ConsolePort), - ("consoleserverporttemplates", "consoleserverports", ConsoleServerPort), - ("interfacetemplates", "interfaces", Interface), - ("powerporttemplates", "powerports", PowerPort), - ("poweroutlettemplates", "poweroutlets", PowerOutlet), - ("rearporttemplates", "rearports", RearPort), - ("frontporttemplates", "frontports", FrontPort), - ("modulebaytemplates", "modulebays", ModuleBay), - ]: - create_instances = [] - update_instances = [] - - # Prefetch installed components - installed_components = { - component.name: component - for component in getattr(self.device, component_attribute).filter(module__isnull=True) - } - - # Get the template for the module type. - for template in getattr(self.module_type, templates).all(): - template_instance = template.instantiate(device=self.device, module=self) - - if adopt_components: - existing_item = installed_components.get(template_instance.name) - - # Check if there's a component with the same name already - if existing_item: - # Assign it to the module - existing_item.module = self - update_instances.append(existing_item) - continue - - # Only create new components if replication is enabled - if not disable_replication: - create_instances.append(template_instance) - - # Set default values for any applicable custom fields - if cf_defaults := CustomField.objects.get_defaults_for_model(component_model): - for component in create_instances: - component.custom_field_data = cf_defaults - - if component_model is not ModuleBay: - component_model.objects.bulk_create(create_instances) - # Emit the post_save signal for each newly created object - for component in create_instances: - post_save.send( - sender=component_model, - instance=component, - created=True, - raw=False, - using='default', - update_fields=None - ) - else: - # ModuleBays must be saved individually for MPTT - for instance in create_instances: - instance.save() - - update_fields = ['module'] - component_model.objects.bulk_update(update_instances, update_fields) - # Emit the post_save signal for each updated object - for component in update_instances: - post_save.send( - sender=component_model, - instance=component, - created=False, - raw=False, - using='default', - update_fields=update_fields - ) - - # Interface bridges have to be set after interface instantiation - update_interface_bridges(self.device, self.module_type.interfacetemplates, self) - - # # Virtual chassis # @@ -1501,7 +1225,6 @@ class MACAddress(PrimaryModel): ) assigned_object_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=MACADDRESS_ASSIGNMENT_MODELS, on_delete=models.PROTECT, related_name='+', blank=True, diff --git a/netbox/dcim/models/mixins.py b/netbox/dcim/models/mixins.py index a0fc15a2585..127dfb9e558 100644 --- a/netbox/dcim/models/mixins.py +++ b/netbox/dcim/models/mixins.py @@ -3,7 +3,6 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ -from dcim.constants import LOCATION_SCOPE_TYPES __all__ = ( 'CachedScopeMixin', @@ -44,7 +43,6 @@ class CachedScopeMixin(models.Model): scope_type = models.ForeignKey( to='contenttypes.ContentType', on_delete=models.PROTECT, - limit_choices_to=models.Q(model__in=LOCATION_SCOPE_TYPES), related_name='+', blank=True, null=True diff --git a/netbox/dcim/models/modules.py b/netbox/dcim/models/modules.py new file mode 100644 index 00000000000..432b7afd164 --- /dev/null +++ b/netbox/dcim/models/modules.py @@ -0,0 +1,360 @@ +import jsonschema +import yaml +from django.core.exceptions import ValidationError +from django.db import models +from django.db.models.signals import post_save +from django.utils.translation import gettext_lazy as _ +from jsonschema.exceptions import ValidationError as JSONValidationError + +from dcim.choices import * +from dcim.utils import update_interface_bridges +from extras.models import ConfigContextModel, CustomField +from netbox.models import PrimaryModel +from netbox.models.features import ImageAttachmentsMixin +from netbox.models.mixins import WeightMixin +from utilities.jsonschema import validate_schema +from utilities.string import title +from .device_components import * + +__all__ = ( + 'Module', + 'ModuleType', + 'ModuleTypeProfile', +) + + +class ModuleTypeProfile(PrimaryModel): + """ + A profile which defines the attributes which can be set on one or more ModuleTypes. + """ + name = models.CharField( + verbose_name=_('name'), + max_length=100, + unique=True + ) + schema = models.JSONField( + blank=True, + null=True, + verbose_name=_('schema') + ) + + clone_fields = ('schema',) + + class Meta: + ordering = ('name',) + verbose_name = _('module type profile') + verbose_name_plural = _('module type profiles') + + def __str__(self): + return self.name + + def clean(self): + super().clean() + + # Validate the schema definition + if self.schema is not None: + try: + validate_schema(self.schema) + except ValidationError as e: + raise ValidationError({ + 'schema': e.message, + }) + + +class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): + """ + A ModuleType represents a hardware element that can be installed within a device and which houses additional + components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a + DeviceType, each ModuleType can have console, power, interface, and pass-through port templates assigned to it. It + cannot, however house device bays or module bays. + """ + profile = models.ForeignKey( + to='dcim.ModuleTypeProfile', + on_delete=models.PROTECT, + related_name='module_types', + blank=True, + null=True + ) + manufacturer = models.ForeignKey( + to='dcim.Manufacturer', + on_delete=models.PROTECT, + related_name='module_types' + ) + model = models.CharField( + verbose_name=_('model'), + max_length=100 + ) + part_number = models.CharField( + verbose_name=_('part number'), + max_length=50, + blank=True, + help_text=_('Discrete part number (optional)') + ) + airflow = models.CharField( + verbose_name=_('airflow'), + max_length=50, + choices=ModuleAirflowChoices, + blank=True, + null=True + ) + attribute_data = models.JSONField( + blank=True, + null=True, + verbose_name=_('attributes') + ) + + clone_fields = ('profile', 'manufacturer', 'weight', 'weight_unit', 'airflow') + prerequisite_models = ( + 'dcim.Manufacturer', + ) + + class Meta: + ordering = ('profile', 'manufacturer', 'model') + constraints = ( + models.UniqueConstraint( + fields=('manufacturer', 'model'), + name='%(app_label)s_%(class)s_unique_manufacturer_model' + ), + ) + verbose_name = _('module type') + verbose_name_plural = _('module types') + + def __str__(self): + return self.model + + @property + def full_name(self): + return f"{self.manufacturer} {self.model}" + + @property + def attributes(self): + """ + Returns a human-friendly representation of the attributes defined for a ModuleType according to its profile. + """ + if not self.attribute_data or self.profile is None or not self.profile.schema: + return {} + attrs = {} + for name, options in self.profile.schema.get('properties', {}).items(): + key = options.get('title', title(name)) + attrs[key] = self.attribute_data.get(name) + return dict(sorted(attrs.items())) + + def clean(self): + super().clean() + + # Validate any attributes against the assigned profile's schema + if self.profile: + try: + jsonschema.validate(self.attribute_data, schema=self.profile.schema) + except JSONValidationError as e: + raise ValidationError(_("Invalid schema: {error}").format(error=e)) + else: + self.attribute_data = None + + def to_yaml(self): + data = { + 'profile': self.profile.name if self.profile else None, + 'manufacturer': self.manufacturer.name, + 'model': self.model, + 'part_number': self.part_number, + 'description': self.description, + 'weight': float(self.weight) if self.weight is not None else None, + 'weight_unit': self.weight_unit, + 'comments': self.comments, + } + + # Component templates + if self.consoleporttemplates.exists(): + data['console-ports'] = [ + c.to_yaml() for c in self.consoleporttemplates.all() + ] + if self.consoleserverporttemplates.exists(): + data['console-server-ports'] = [ + c.to_yaml() for c in self.consoleserverporttemplates.all() + ] + if self.powerporttemplates.exists(): + data['power-ports'] = [ + c.to_yaml() for c in self.powerporttemplates.all() + ] + if self.poweroutlettemplates.exists(): + data['power-outlets'] = [ + c.to_yaml() for c in self.poweroutlettemplates.all() + ] + if self.interfacetemplates.exists(): + data['interfaces'] = [ + c.to_yaml() for c in self.interfacetemplates.all() + ] + if self.frontporttemplates.exists(): + data['front-ports'] = [ + c.to_yaml() for c in self.frontporttemplates.all() + ] + if self.rearporttemplates.exists(): + data['rear-ports'] = [ + c.to_yaml() for c in self.rearporttemplates.all() + ] + + return yaml.dump(dict(data), sort_keys=False) + + +class Module(PrimaryModel, ConfigContextModel): + """ + A Module represents a field-installable component within a Device which may itself hold multiple device components + (for example, a line card within a chassis switch). Modules are instantiated from ModuleTypes. + """ + device = models.ForeignKey( + to='dcim.Device', + on_delete=models.CASCADE, + related_name='modules' + ) + module_bay = models.OneToOneField( + to='dcim.ModuleBay', + on_delete=models.CASCADE, + related_name='installed_module' + ) + module_type = models.ForeignKey( + to='dcim.ModuleType', + on_delete=models.PROTECT, + related_name='instances' + ) + status = models.CharField( + verbose_name=_('status'), + max_length=50, + choices=ModuleStatusChoices, + default=ModuleStatusChoices.STATUS_ACTIVE + ) + serial = models.CharField( + max_length=50, + blank=True, + verbose_name=_('serial number') + ) + asset_tag = models.CharField( + max_length=50, + blank=True, + null=True, + unique=True, + verbose_name=_('asset tag'), + help_text=_('A unique tag used to identify this device') + ) + + clone_fields = ('device', 'module_type', 'status') + + class Meta: + ordering = ('module_bay',) + verbose_name = _('module') + verbose_name_plural = _('modules') + + def __str__(self): + return f'{self.module_bay.name}: {self.module_type} ({self.pk})' + + def get_status_color(self): + return ModuleStatusChoices.colors.get(self.status) + + def clean(self): + super().clean() + + if hasattr(self, "module_bay") and (self.module_bay.device != self.device): + raise ValidationError( + _("Module must be installed within a module bay belonging to the assigned device ({device}).").format( + device=self.device + ) + ) + + # Check for recursion + module = self + module_bays = [] + modules = [] + while module: + if module.pk in modules or module.module_bay.pk in module_bays: + raise ValidationError(_("A module bay cannot belong to a module installed within it.")) + modules.append(module.pk) + module_bays.append(module.module_bay.pk) + module = module.module_bay.module if module.module_bay else None + + def save(self, *args, **kwargs): + is_new = self.pk is None + + super().save(*args, **kwargs) + + adopt_components = getattr(self, '_adopt_components', False) + disable_replication = getattr(self, '_disable_replication', False) + + # We skip adding components if the module is being edited or + # both replication and component adoption is disabled + if not is_new or (disable_replication and not adopt_components): + return + + # Iterate all component types + for templates, component_attribute, component_model in [ + ("consoleporttemplates", "consoleports", ConsolePort), + ("consoleserverporttemplates", "consoleserverports", ConsoleServerPort), + ("interfacetemplates", "interfaces", Interface), + ("powerporttemplates", "powerports", PowerPort), + ("poweroutlettemplates", "poweroutlets", PowerOutlet), + ("rearporttemplates", "rearports", RearPort), + ("frontporttemplates", "frontports", FrontPort), + ("modulebaytemplates", "modulebays", ModuleBay), + ]: + create_instances = [] + update_instances = [] + + # Prefetch installed components + installed_components = { + component.name: component + for component in getattr(self.device, component_attribute).filter(module__isnull=True) + } + + # Get the template for the module type. + for template in getattr(self.module_type, templates).all(): + template_instance = template.instantiate(device=self.device, module=self) + + if adopt_components: + existing_item = installed_components.get(template_instance.name) + + # Check if there's a component with the same name already + if existing_item: + # Assign it to the module + existing_item.module = self + update_instances.append(existing_item) + continue + + # Only create new components if replication is enabled + if not disable_replication: + create_instances.append(template_instance) + + # Set default values for any applicable custom fields + if cf_defaults := CustomField.objects.get_defaults_for_model(component_model): + for component in create_instances: + component.custom_field_data = cf_defaults + + if component_model is not ModuleBay: + component_model.objects.bulk_create(create_instances) + # Emit the post_save signal for each newly created object + for component in create_instances: + post_save.send( + sender=component_model, + instance=component, + created=True, + raw=False, + using='default', + update_fields=None + ) + else: + # ModuleBays must be saved individually for MPTT + for instance in create_instances: + instance.save() + + update_fields = ['module'] + component_model.objects.bulk_update(update_instances, update_fields) + # Emit the post_save signal for each updated object + for component in update_instances: + post_save.send( + sender=component_model, + instance=component, + created=False, + raw=False, + using='default', + update_fields=update_fields + ) + + # Interface bridges have to be set after interface instantiation + update_interface_bridges(self.device, self.module_type.interfacetemplates, self) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 7ecbd5d5f87..390d9ae9ea8 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -73,6 +73,12 @@ class RackBase(WeightMixin, PrimaryModel): null=True, help_text=_('Outer dimension of rack (width)') ) + outer_height = models.PositiveSmallIntegerField( + verbose_name=_('outer height'), + blank=True, + null=True, + help_text=_('Outer dimension of rack (height)') + ) outer_depth = models.PositiveSmallIntegerField( verbose_name=_('outer depth'), blank=True, @@ -140,7 +146,7 @@ class RackType(RackBase): ) clone_fields = ( - 'manufacturer', 'form_factor', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', + 'manufacturer', 'form_factor', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', ) prerequisite_models = ( @@ -173,8 +179,8 @@ class RackType(RackBase): super().clean() # Validate outer dimensions and unit - if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: - raise ValidationError(_("Must specify a unit when setting an outer width/depth")) + if any([self.outer_width, self.outer_depth, self.outer_height]) and not self.outer_unit: + raise ValidationError(_("Must specify a unit when setting an outer dimension")) # Validate max_weight and weight_unit if self.max_weight and not self.weight_unit: @@ -188,7 +194,7 @@ class RackType(RackBase): self._abs_max_weight = None # Clear unit if outer width & depth are not set - if self.outer_width is None and self.outer_depth is None: + if not any([self.outer_width, self.outer_depth, self.outer_height]): self.outer_unit = None super().save(*args, **kwargs) @@ -235,8 +241,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): """ # Fields which cannot be set locally if a RackType is assigned RACKTYPE_FIELDS = ( - 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', - 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'max_weight', + 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', + 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'max_weight', ) form_factor = models.CharField( @@ -329,7 +335,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): clone_fields = ( 'site', 'location', 'tenant', 'status', 'role', 'form_factor', 'width', 'airflow', 'u_height', 'desc_units', - 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', + 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', + 'weight_unit', ) prerequisite_models = ( 'dcim.Site', @@ -364,8 +371,8 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): raise ValidationError(_("Assigned location must belong to parent site ({site}).").format(site=self.site)) # Validate outer dimensions and unit - if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: - raise ValidationError(_("Must specify a unit when setting an outer width/depth")) + if any([self.outer_width, self.outer_depth, self.outer_height]) and not self.outer_unit: + raise ValidationError(_("Must specify a unit when setting an outer dimension")) # Validate max_weight and weight_unit if self.max_weight and not self.weight_unit: @@ -414,7 +421,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): self._abs_max_weight = None # Clear unit if outer width & depth are not set - if self.outer_width is None and self.outer_depth is None: + if not any([self.outer_width, self.outer_depth, self.outer_height]): self.outer_unit = None super().save(*args, **kwargs) diff --git a/netbox/dcim/search.py b/netbox/dcim/search.py index b964421de05..33b666df7a7 100644 --- a/netbox/dcim/search.py +++ b/netbox/dcim/search.py @@ -144,6 +144,7 @@ class LocationIndex(SearchIndex): ('facility', 100), ('slug', 110), ('description', 500), + ('comments', 5000), ) display_attrs = ('site', 'status', 'tenant', 'facility', 'description') @@ -182,6 +183,17 @@ class ModuleBayIndex(SearchIndex): display_attrs = ('device', 'label', 'position', 'description') +@register_search +class ModuleTypeProfileIndex(SearchIndex): + model = models.ModuleTypeProfile + fields = ( + ('name', 100), + ('description', 500), + ('comments', 5000), + ) + display_attrs = ('name', 'description') + + @register_search class ModuleTypeIndex(SearchIndex): model = models.ModuleType @@ -224,7 +236,7 @@ class PowerOutletIndex(SearchIndex): ('label', 200), ('description', 500), ) - display_attrs = ('device', 'label', 'type', 'description') + display_attrs = ('device', 'label', 'type', 'status', 'description') @register_search @@ -317,6 +329,7 @@ class RegionIndex(SearchIndex): ('name', 100), ('slug', 110), ('description', 500), + ('comments', 5000), ) display_attrs = ('parent', 'description') @@ -343,6 +356,7 @@ class SiteGroupIndex(SearchIndex): ('name', 100), ('slug', 110), ('description', 500), + ('comments', 5000), ) display_attrs = ('parent', 'description') diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index d4f2f74b3fd..5cfb3175089 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -59,7 +59,7 @@ MACADDRESS_COPY_BUTTON = """ # class DeviceRoleTable(NetBoxTable): - name = tables.Column( + name = columns.MPTTColumn( verbose_name=_('Name'), linkify=True ) @@ -520,6 +520,9 @@ class PowerOutletTable(ModularDeviceComponentTable, PathEndpointTable): verbose_name=_('Power Port'), linkify=True ) + status = columns.ChoiceFieldColumn( + verbose_name=_('Status'), + ) color = columns.ColorColumn() tags = columns.TagColumn( url_name='dcim:poweroutlet_list' @@ -530,9 +533,11 @@ class PowerOutletTable(ModularDeviceComponentTable, PathEndpointTable): fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'power_port', 'color', 'feed_leg', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', - 'tags', 'created', 'last_updated', + 'tags', 'created', 'last_updated', 'status', + ) + default_columns = ( + 'pk', 'name', 'device', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'description', ) - default_columns = ('pk', 'name', 'device', 'label', 'type', 'color', 'power_port', 'feed_leg', 'description') class DevicePowerOutletTable(PowerOutletTable): @@ -550,9 +555,11 @@ class DevicePowerOutletTable(PowerOutletTable): fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'color', 'power_port', 'feed_leg', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions', + 'status', ) default_columns = ( - 'pk', 'name', 'label', 'type', 'color', 'power_port', 'feed_leg', 'description', 'cable', 'connection', + 'pk', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'description', 'cable', + 'connection', ) diff --git a/netbox/dcim/tables/modules.py b/netbox/dcim/tables/modules.py index 6bd0d53b5e0..52edea8b41e 100644 --- a/netbox/dcim/tables/modules.py +++ b/netbox/dcim/tables/modules.py @@ -1,25 +1,64 @@ from django.utils.translation import gettext_lazy as _ import django_tables2 as tables -from dcim.models import Module, ModuleType +from dcim.models import Module, ModuleType, ModuleTypeProfile from netbox.tables import NetBoxTable, columns -from .template_code import WEIGHT +from .template_code import MODULETYPEPROFILE_ATTRIBUTES, WEIGHT __all__ = ( 'ModuleTable', + 'ModuleTypeProfileTable', 'ModuleTypeTable', ) +class ModuleTypeProfileTable(NetBoxTable): + name = tables.Column( + verbose_name=_('Name'), + linkify=True + ) + attributes = columns.TemplateColumn( + template_code=MODULETYPEPROFILE_ATTRIBUTES, + accessor=tables.A('schema__properties'), + orderable=False, + verbose_name=_('Attributes') + ) + comments = columns.MarkdownColumn( + verbose_name=_('Comments'), + ) + tags = columns.TagColumn( + url_name='dcim:moduletypeprofile_list' + ) + + class Meta(NetBoxTable.Meta): + model = ModuleTypeProfile + fields = ( + 'pk', 'id', 'name', 'description', 'comments', 'tags', 'created', 'last_updated', + ) + default_columns = ( + 'pk', 'name', 'description', 'attributes', + ) + + class ModuleTypeTable(NetBoxTable): - model = tables.Column( - linkify=True, - verbose_name=_('Module Type') + profile = tables.Column( + verbose_name=_('Profile'), + linkify=True ) manufacturer = tables.Column( verbose_name=_('Manufacturer'), linkify=True ) + model = tables.Column( + linkify=True, + verbose_name=_('Module Type') + ) + weight = columns.TemplateColumn( + verbose_name=_('Weight'), + template_code=WEIGHT, + order_by=('_abs_weight', 'weight_unit') + ) + attributes = columns.DictColumn() instance_count = columns.LinkedCountColumn( viewname='dcim:module_list', url_params={'module_type_id': 'pk'}, @@ -31,20 +70,15 @@ class ModuleTypeTable(NetBoxTable): tags = columns.TagColumn( url_name='dcim:moduletype_list' ) - weight = columns.TemplateColumn( - verbose_name=_('Weight'), - template_code=WEIGHT, - order_by=('_abs_weight', 'weight_unit') - ) class Meta(NetBoxTable.Meta): model = ModuleType fields = ( - 'pk', 'id', 'model', 'manufacturer', 'part_number', 'airflow', 'weight', 'description', 'comments', 'tags', - 'created', 'last_updated', + 'pk', 'id', 'model', 'profile', 'manufacturer', 'part_number', 'airflow', 'weight', 'description', + 'attributes', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( - 'pk', 'model', 'manufacturer', 'part_number', + 'pk', 'model', 'profile', 'manufacturer', 'part_number', ) diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index dbd99ca246c..ee40056de75 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -5,7 +5,7 @@ from django_tables2.utils import Accessor from dcim.models import Rack, RackReservation, RackRole, RackType from netbox.tables import NetBoxTable, columns from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin -from .template_code import WEIGHT +from .template_code import OUTER_UNIT, WEIGHT __all__ = ( 'RackTable', @@ -62,12 +62,16 @@ class RackTypeTable(NetBoxTable): template_code="{{ value }}U", verbose_name=_('Height') ) - outer_width = tables.TemplateColumn( - template_code="{{ record.outer_width }} {{ record.outer_unit }}", + outer_width = columns.TemplateColumn( + template_code=OUTER_UNIT, verbose_name=_('Outer Width') ) - outer_depth = tables.TemplateColumn( - template_code="{{ record.outer_depth }} {{ record.outer_unit }}", + outer_height = columns.TemplateColumn( + template_code=OUTER_UNIT, + verbose_name=_('Outer Height') + ) + outer_depth = columns.TemplateColumn( + template_code=OUTER_UNIT, verbose_name=_('Outer Depth') ) weight = columns.TemplateColumn( @@ -96,8 +100,8 @@ class RackTypeTable(NetBoxTable): model = RackType fields = ( 'pk', 'id', 'model', 'manufacturer', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width', - 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'description', 'comments', - 'instance_count', 'tags', 'created', 'last_updated', + 'outer_height', 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'description', + 'comments', 'instance_count', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'model', 'manufacturer', 'type', 'u_height', 'description', 'instance_count', @@ -159,12 +163,16 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): tags = columns.TagColumn( url_name='dcim:rack_list' ) - outer_width = tables.TemplateColumn( - template_code="{{ record.outer_width }} {{ record.outer_unit }}", + outer_width = columns.TemplateColumn( + template_code=OUTER_UNIT, verbose_name=_('Outer Width') ) - outer_depth = tables.TemplateColumn( - template_code="{{ record.outer_depth }} {{ record.outer_unit }}", + outer_height = columns.TemplateColumn( + template_code=OUTER_UNIT, + verbose_name=_('Outer Height') + ) + outer_depth = columns.TemplateColumn( + template_code=OUTER_UNIT, verbose_name=_('Outer Depth') ) weight = columns.TemplateColumn( @@ -183,8 +191,9 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): fields = ( 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'rack_type', 'serial', 'asset_tag', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width', - 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'comments', 'device_count', - 'get_utilization', 'get_power_utilization', 'description', 'contacts', 'tags', 'created', 'last_updated', + 'outer_height', 'outer_depth', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'comments', + 'device_count', 'get_utilization', 'get_power_utilization', 'description', 'contacts', + 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'rack_type', 'u_height', diff --git a/netbox/dcim/tables/sites.py b/netbox/dcim/tables/sites.py index 77844f08622..7d2f0e0cc07 100644 --- a/netbox/dcim/tables/sites.py +++ b/netbox/dcim/tables/sites.py @@ -32,12 +32,15 @@ class RegionTable(ContactsColumnMixin, NetBoxTable): tags = columns.TagColumn( url_name='dcim:region_list' ) + comments = columns.MarkdownColumn( + verbose_name=_('Comments'), + ) class Meta(NetBoxTable.Meta): model = Region fields = ( - 'pk', 'id', 'name', 'slug', 'site_count', 'description', 'contacts', 'tags', 'created', 'last_updated', - 'actions', + 'pk', 'id', 'name', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags', + 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'name', 'site_count', 'description') @@ -59,12 +62,15 @@ class SiteGroupTable(ContactsColumnMixin, NetBoxTable): tags = columns.TagColumn( url_name='dcim:sitegroup_list' ) + comments = columns.MarkdownColumn( + verbose_name=_('Comments'), + ) class Meta(NetBoxTable.Meta): model = SiteGroup fields = ( - 'pk', 'id', 'name', 'slug', 'site_count', 'description', 'contacts', 'tags', 'created', 'last_updated', - 'actions', + 'pk', 'id', 'name', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags', + 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'name', 'site_count', 'description') @@ -153,12 +159,15 @@ class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): actions = columns.ActionsColumn( extra_buttons=LOCATION_BUTTONS ) + comments = columns.MarkdownColumn( + verbose_name=_('Comments'), + ) class Meta(NetBoxTable.Meta): model = Location fields = ( 'pk', 'id', 'name', 'site', 'status', 'facility', 'tenant', 'tenant_group', 'rack_count', 'device_count', - 'description', 'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated', + 'description', 'slug', 'comments', 'contacts', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'site', 'status', 'facility', 'tenant', 'rack_count', 'device_count', 'description' diff --git a/netbox/dcim/tables/template_code.py b/netbox/dcim/tables/template_code.py index 4b51cd06a8b..3c4ca7bd4a6 100644 --- a/netbox/dcim/tables/template_code.py +++ b/netbox/dcim/tables/template_code.py @@ -109,6 +109,11 @@ LOCATION_BUTTONS = """ """ +OUTER_UNIT = """ +{% load helpers %} +{% if value %}{{ value }} {{ record.outer_unit }}{% endif %} +""" + # # Device component templatebuttons # @@ -563,3 +568,7 @@ MODULEBAY_BUTTONS = """ {% endif %} {% endif %} """ + +MODULETYPEPROFILE_ATTRIBUTES = """ +{% if value %}{% for attr in value %}{{ attr }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %} +""" diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 99a446aef5e..8007d916117 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1,3 +1,5 @@ +import json + from django.test import override_settings from django.urls import reverse from django.utils.translation import gettext as _ @@ -72,6 +74,7 @@ class RegionTest(APIViewTestCases.APIViewTestCase): { 'name': 'Region 4', 'slug': 'region-4', + 'comments': 'this is region 4, not region 5', }, { 'name': 'Region 5', @@ -84,13 +87,14 @@ class RegionTest(APIViewTestCases.APIViewTestCase): ] bulk_update_data = { 'description': 'New description', + 'comments': 'New comments', } @classmethod def setUpTestData(cls): Region.objects.create(name='Region 1', slug='region-1') - Region.objects.create(name='Region 2', slug='region-2') + Region.objects.create(name='Region 2', slug='region-2', comments='what in the world is happening?') Region.objects.create(name='Region 3', slug='region-3') @@ -101,26 +105,30 @@ class SiteGroupTest(APIViewTestCases.APIViewTestCase): { 'name': 'Site Group 4', 'slug': 'site-group-4', + 'comments': '', }, { 'name': 'Site Group 5', 'slug': 'site-group-5', + 'comments': 'not actually empty', }, { 'name': 'Site Group 6', 'slug': 'site-group-6', + 'comments': 'Do I really exist?', }, ] bulk_update_data = { 'description': 'New description', + 'comments': 'I do exist!', } @classmethod def setUpTestData(cls): SiteGroup.objects.create(name='Site Group 1', slug='site-group-1') - SiteGroup.objects.create(name='Site Group 2', slug='site-group-2') - SiteGroup.objects.create(name='Site Group 3', slug='site-group-3') + SiteGroup.objects.create(name='Site Group 2', slug='site-group-2', comments='') + SiteGroup.objects.create(name='Site Group 3', slug='site-group-3', comments='Hi!') class SiteTest(APIViewTestCases.APIViewTestCase): @@ -210,12 +218,14 @@ class LocationTest(APIViewTestCases.APIViewTestCase): name='Parent Location 1', slug='parent-location-1', status=LocationStatusChoices.STATUS_ACTIVE, + comments='First!' ), Location.objects.create( site=sites[1], name='Parent Location 2', slug='parent-location-2', status=LocationStatusChoices.STATUS_ACTIVE, + comments='Second!' ), ) @@ -225,6 +235,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase): slug='location-1', parent=parent_locations[0], status=LocationStatusChoices.STATUS_ACTIVE, + comments='Third!' ) Location.objects.create( site=sites[0], @@ -248,6 +259,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase): 'site': sites[1].pk, 'parent': parent_locations[1].pk, 'status': LocationStatusChoices.STATUS_PLANNED, + 'comments': '', }, { 'name': 'Test Location 5', @@ -255,6 +267,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase): 'site': sites[1].pk, 'parent': parent_locations[1].pk, 'status': LocationStatusChoices.STATUS_PLANNED, + 'comments': 'Somebody should check on this location', }, { 'name': 'Test Location 6', @@ -578,7 +591,7 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase): class ModuleTypeTest(APIViewTestCases.APIViewTestCase): model = ModuleType - brief_fields = ['description', 'display', 'id', 'manufacturer', 'model', 'url'] + brief_fields = ['description', 'display', 'id', 'manufacturer', 'model', 'profile', 'url'] bulk_update_data = { 'part_number': 'ABC123', } @@ -616,6 +629,70 @@ class ModuleTypeTest(APIViewTestCases.APIViewTestCase): ] +class ModuleTypeProfileTest(APIViewTestCases.APIViewTestCase): + model = ModuleTypeProfile + brief_fields = ['description', 'display', 'id', 'name', 'url'] + SCHEMAS = [ + { + "properties": { + "foo": { + "type": "string" + } + } + }, + { + "properties": { + "foo": { + "type": "integer" + } + } + }, + { + "properties": { + "foo": { + "type": "boolean" + } + } + }, + ] + create_data = [ + { + 'name': 'Module Type Profile 4', + 'schema': SCHEMAS[0], + }, + { + 'name': 'Module Type Profile 5', + 'schema': SCHEMAS[1], + }, + { + 'name': 'Module Type Profile 6', + 'schema': SCHEMAS[2], + }, + ] + bulk_update_data = { + 'description': 'New description', + 'comments': 'New comments', + } + + @classmethod + def setUpTestData(cls): + module_type_profiles = ( + ModuleTypeProfile( + name='Module Type Profile 1', + schema=cls.SCHEMAS[0] + ), + ModuleTypeProfile( + name='Module Type Profile 2', + schema=cls.SCHEMAS[1] + ), + ModuleTypeProfile( + name='Module Type Profile 3', + schema=cls.SCHEMAS[2] + ), + ) + ModuleTypeProfile.objects.bulk_create(module_type_profiles) + + class ConsolePortTemplateTest(APIViewTestCases.APIViewTestCase): model = ConsolePortTemplate brief_fields = ['description', 'display', 'id', 'name', 'url'] @@ -1136,7 +1213,9 @@ class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase): class DeviceRoleTest(APIViewTestCases.APIViewTestCase): model = DeviceRole - brief_fields = ['description', 'device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count'] + brief_fields = [ + '_depth', 'description', 'device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count' + ] create_data = [ { 'name': 'Device Role 4', @@ -1161,12 +1240,9 @@ class DeviceRoleTest(APIViewTestCases.APIViewTestCase): @classmethod def setUpTestData(cls): - roles = ( - DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000'), - DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00'), - DeviceRole(name='Device Role 3', slug='device-role-3', color='0000ff'), - ) - DeviceRole.objects.bulk_create(roles) + DeviceRole.objects.create(name='Device Role 1', slug='device-role-1', color='ff0000') + DeviceRole.objects.create(name='Device Role 2', slug='device-role-2', color='00ff00') + DeviceRole.objects.create(name='Device Role 3', slug='device-role-3', color='0000ff') class PlatformTest(APIViewTestCases.APIViewTestCase): @@ -1239,7 +1315,8 @@ class DeviceTest(APIViewTestCases.APIViewTestCase): DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000'), DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1') @@ -1748,6 +1825,23 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase }, ] + def _perform_interface_test_with_invalid_data(self, mode: str = None, invalid_data: dict = {}): + device = Device.objects.first() + data = { + 'device': device.pk, + 'name': 'Interface 1', + 'type': InterfaceTypeChoices.TYPE_1GE_FIXED, + } + data.update({'mode': mode}) + data.update(invalid_data) + + response = self.client.post(self._get_list_url(), data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + content = json.loads(response.content) + for key in invalid_data.keys(): + self.assertIn(key, content) + self.assertIsNone(content.get('data')) + def test_bulk_delete_child_interfaces(self): interface1 = Interface.objects.get(name='Interface 1') device = interface1.device @@ -1775,6 +1869,57 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase self.client.delete(self._get_list_url(), data, format='json', **self.header) self.assertEqual(device.interfaces.count(), 2) # Child & parent were both deleted + def test_create_child_interfaces_mode_invalid_data(self): + """ + POST data to test interface mode check and invalid tagged/untagged VLANS. + """ + self.add_permissions('dcim.add_interface') + + vlans = VLAN.objects.all()[0:3] + + # Routed mode, untagged, tagged and qinq service vlan + invalid_data = { + 'untagged_vlan': vlans[0].pk, + 'tagged_vlans': [vlans[1].pk, vlans[2].pk], + 'qinq_svlan': vlans[2].pk + } + self._perform_interface_test_with_invalid_data(None, invalid_data) + + # Routed mode, untagged and tagged vlan + invalid_data = { + 'untagged_vlan': vlans[0].pk, + 'tagged_vlans': [vlans[1].pk, vlans[2].pk], + } + self._perform_interface_test_with_invalid_data(None, invalid_data) + + # Routed mode, untagged vlan + invalid_data = { + 'untagged_vlan': vlans[0].pk, + } + self._perform_interface_test_with_invalid_data(None, invalid_data) + + invalid_data = { + 'tagged_vlans': [vlans[1].pk, vlans[2].pk], + } + # Routed mode, qinq service vlan + self._perform_interface_test_with_invalid_data(None, invalid_data) + # Access mode, tagged vlans + self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_ACCESS, invalid_data) + # All tagged mode, tagged vlans + self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED_ALL, invalid_data) + + invalid_data = { + 'qinq_svlan': vlans[0].pk, + } + # Routed mode, qinq service vlan + self._perform_interface_test_with_invalid_data(None, invalid_data) + # Access mode, qinq service vlan + self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_ACCESS, invalid_data) + # Tagged mode, qinq service vlan + self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED, invalid_data) + # Tagged-all mode, qinq service vlan + self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED_ALL, invalid_data) + class FrontPortTest(APIViewTestCases.APIViewTestCase): model = FrontPort diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index ede1e2a09d3..b56ea39191a 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -67,9 +67,15 @@ class RegionTestCase(TestCase, ChangeLoggedFilterSetTests): def setUpTestData(cls): parent_regions = ( - Region(name='Region 1', slug='region-1', description='foobar1'), - Region(name='Region 2', slug='region-2', description='foobar2'), - Region(name='Region 3', slug='region-3', description='foobar3'), + Region( + name='Region 1', slug='region-1', description='foobar1', comments="There's nothing that", + ), + Region( + name='Region 2', slug='region-2', description='foobar2', comments='a hundred men or more', + ), + Region( + name='Region 3', slug='region-3', description='foobar3', comments='could ever do' + ), ) for region in parent_regions: region.save() @@ -100,6 +106,13 @@ class RegionTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'q': 'foobar1'} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_q_comments(self): + params = {'q': 'there'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'q': 'hundred men could'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0) + def test_name(self): params = {'name': ['Region 1', 'Region 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) @@ -148,13 +161,17 @@ class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests): SiteGroup(name='Site Group 2A', slug='site-group-2a', parent=parent_groups[1]), SiteGroup(name='Site Group 2B', slug='site-group-2b', parent=parent_groups[1]), SiteGroup(name='Site Group 3A', slug='site-group-3a', parent=parent_groups[2]), - SiteGroup(name='Site Group 3B', slug='site-group-3b', parent=parent_groups[2]), + SiteGroup( + name='Site Group 3B', slug='site-group-3b', parent=parent_groups[2], comments='this is a parent group', + ), ) for site_group in groups: site_group.save() child_groups = ( - SiteGroup(name='Site Group 1A1', slug='site-group-1a1', parent=groups[0]), + SiteGroup( + name='Site Group 1A1', slug='site-group-1a1', parent=groups[0], comments='this is a child group', + ), SiteGroup(name='Site Group 1B1', slug='site-group-1b1', parent=groups[1]), SiteGroup(name='Site Group 2A1', slug='site-group-2a1', parent=groups[2]), SiteGroup(name='Site Group 2B1', slug='site-group-2b1', parent=groups[3]), @@ -168,6 +185,13 @@ class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'q': 'foobar1'} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_q_comments(self): + params = {'q': 'this'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + params = {'q': 'child'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_name(self): params = {'name': ['Site Group 1', 'Site Group 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) @@ -401,6 +425,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests): status=LocationStatusChoices.STATUS_PLANNED, facility='Facility 1', description='foobar1', + comments='', ), Location( name='Location 2A', @@ -410,6 +435,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests): status=LocationStatusChoices.STATUS_STAGING, facility='Facility 2', description='foobar2', + comments='First comment!', ), Location( name='Location 3A', @@ -419,6 +445,7 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests): status=LocationStatusChoices.STATUS_DECOMMISSIONING, facility='Facility 3', description='foobar3', + comments='_This_ is a **bold comment**', ), ) for location in locations: @@ -436,6 +463,13 @@ class LocationTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'q': 'foobar1'} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_q_comments(self): + params = {'q': 'this'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'q': 'comment'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_name(self): params = {'name': ['Location 1', 'Location 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) @@ -551,6 +585,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): starting_unit=1, desc_units=False, outer_width=100, + outer_height=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, mounting_depth=100, @@ -569,6 +604,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): starting_unit=2, desc_units=False, outer_width=200, + outer_height=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, mounting_depth=200, @@ -587,6 +623,7 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): starting_unit=3, desc_units=True, outer_width=300, + outer_height=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH, mounting_depth=300, @@ -647,6 +684,10 @@ class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'outer_width': [100, 200]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_outer_height(self): + params = {'outer_height': [100, 200]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_outer_depth(self): params = {'outer_depth': [100, 200]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) @@ -730,6 +771,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): starting_unit=1, desc_units=False, outer_width=100, + outer_height=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, mounting_depth=100, @@ -748,6 +790,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): starting_unit=2, desc_units=False, outer_width=200, + outer_height=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, mounting_depth=200, @@ -797,6 +840,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): u_height=42, desc_units=False, outer_width=100, + outer_height=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, weight=10, @@ -820,6 +864,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): u_height=43, desc_units=False, outer_width=200, + outer_height=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, weight=20, @@ -843,6 +888,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): u_height=44, desc_units=True, outer_width=300, + outer_height=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH, weight=30, @@ -923,6 +969,10 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'outer_width': [100, 200]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_outer_height(self): + params = {'outer_height': [100, 200]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_outer_depth(self): params = {'outer_depth': [100, 200]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) @@ -1436,6 +1486,16 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests): class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = ModuleType.objects.all() filterset = ModuleTypeFilterSet + ignore_fields = ['attribute_data'] + + PROFILE_SCHEMA = { + "properties": { + "string": {"type": "string"}, + "integer": {"type": "integer"}, + "number": {"type": "number"}, + "boolean": {"type": "boolean"}, + } + } @classmethod def setUpTestData(cls): @@ -1446,6 +1506,21 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): Manufacturer(name='Manufacturer 3', slug='manufacturer-3'), ) Manufacturer.objects.bulk_create(manufacturers) + module_type_profiles = ( + ModuleTypeProfile( + name='Module Type Profile 1', + schema=cls.PROFILE_SCHEMA + ), + ModuleTypeProfile( + name='Module Type Profile 2', + schema=cls.PROFILE_SCHEMA + ), + ModuleTypeProfile( + name='Module Type Profile 3', + schema=cls.PROFILE_SCHEMA + ), + ) + ModuleTypeProfile.objects.bulk_create(module_type_profiles) module_types = ( ModuleType( @@ -1455,7 +1530,14 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): weight=10, weight_unit=WeightUnitChoices.UNIT_POUND, description='foobar1', - airflow=ModuleAirflowChoices.FRONT_TO_REAR + airflow=ModuleAirflowChoices.FRONT_TO_REAR, + profile=module_type_profiles[0], + attribute_data={ + 'string': 'string1', + 'integer': 1, + 'number': 1.0, + 'boolean': True, + } ), ModuleType( manufacturer=manufacturers[1], @@ -1464,7 +1546,14 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): weight=20, weight_unit=WeightUnitChoices.UNIT_POUND, description='foobar2', - airflow=ModuleAirflowChoices.REAR_TO_FRONT + airflow=ModuleAirflowChoices.REAR_TO_FRONT, + profile=module_type_profiles[1], + attribute_data={ + 'string': 'string2', + 'integer': 2, + 'number': 2.0, + 'boolean_': False, + } ), ModuleType( manufacturer=manufacturers[2], @@ -1472,7 +1561,14 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): part_number='Part Number 3', weight=30, weight_unit=WeightUnitChoices.UNIT_KILOGRAM, - description='foobar3' + description='foobar3', + profile=module_type_profiles[2], + attribute_data={ + 'string': 'string3', + 'integer': 3, + 'number': 3.0, + 'boolean': None, + } ), ) ModuleType.objects.bulk_create(module_types) @@ -1591,6 +1687,82 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'airflow': RackAirflowChoices.FRONT_TO_REAR} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_profile(self): + profiles = ModuleTypeProfile.objects.filter(name__startswith="Module Type Profile")[:2] + params = {'profile_id': [profiles[0].pk, profiles[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'profile': [profiles[0].name, profiles[1].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_profile_attributes(self): + params = {'attr_string': 'string1'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + params = {'attr_integer': '1'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + params = {'attr_number': '2.0'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + params = {'attr_boolean': 'true'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + +class ModuleTypeProfileTestCase(TestCase, ChangeLoggedFilterSetTests): + queryset = ModuleTypeProfile.objects.all() + filterset = ModuleTypeProfileFilterSet + ignore_fields = ['schema'] + + SCHEMAS = [ + { + "properties": { + "foo": { + "type": "string" + } + } + }, + { + "properties": { + "foo": { + "type": "integer" + } + } + }, + { + "properties": { + "foo": { + "type": "boolean" + } + } + }, + ] + + @classmethod + def setUpTestData(cls): + module_type_profiles = ( + ModuleTypeProfile( + name='Module Type Profile 1', + description='foobar1', + schema=cls.SCHEMAS[0] + ), + ModuleTypeProfile( + name='Module Type Profile 2', + description='foobar2 2', + schema=cls.SCHEMAS[1] + ), + ModuleTypeProfile( + name='Module Type Profile 3', + description='foobar3', + schema=cls.SCHEMAS[2] + ), + ) + ModuleTypeProfile.objects.bulk_create(module_type_profiles) + + def test_q(self): + params = {'q': 'foobar1'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + def test_name(self): + params = {'name': ['Module Type Profile 1', 'Module Type Profile 2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + class ConsolePortTemplateTestCase(TestCase, DeviceComponentTemplateFilterSetTests, ChangeLoggedFilterSetTests): queryset = ConsolePortTemplate.objects.all() @@ -2141,12 +2313,65 @@ class DeviceRoleTestCase(TestCase, ChangeLoggedFilterSetTests): @classmethod def setUpTestData(cls): - roles = ( + parent_roles = ( DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000', vm_role=True, description='foobar1'), DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00', vm_role=True, description='foobar2'), - DeviceRole(name='Device Role 3', slug='device-role-3', color='0000ff', vm_role=False), + DeviceRole(name='Device Role 3', slug='device-role-3', color='0000ff', vm_role=False) ) - DeviceRole.objects.bulk_create(roles) + for role in parent_roles: + role.save() + + roles = ( + DeviceRole( + name='Device Role 1A', + slug='device-role-1a', + color='aa0000', + vm_role=True, + parent=parent_roles[0] + ), + DeviceRole( + name='Device Role 2A', + slug='device-role-2a', + color='00aa00', + vm_role=True, + parent=parent_roles[1] + ), + DeviceRole( + name='Device Role 3A', + slug='device-role-3a', + color='0000aa', + vm_role=False, + parent=parent_roles[2] + ) + ) + for role in roles: + role.save() + + child_roles = ( + DeviceRole( + name='Device Role 1A1', + slug='device-role-1a1', + color='bb0000', + vm_role=True, + parent=roles[0] + ), + DeviceRole( + name='Device Role 2A1', + slug='device-role-2a1', + color='00bb00', + vm_role=True, + parent=roles[1] + ), + DeviceRole( + name='Device Role 3A1', + slug='device-role-3a1', + color='0000bb', + vm_role=False, + parent=roles[2] + ) + ) + for role in child_roles: + role.save() def test_q(self): params = {'q': 'foobar1'} @@ -2166,14 +2391,28 @@ class DeviceRoleTestCase(TestCase, ChangeLoggedFilterSetTests): def test_vm_role(self): params = {'vm_role': 'true'} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) params = {'vm_role': 'false'} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) def test_description(self): params = {'description': ['foobar1', 'foobar2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_parent(self): + roles = DeviceRole.objects.filter(parent__isnull=True)[:2] + params = {'parent_id': [roles[0].pk, roles[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'parent': [roles[0].slug, roles[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_ancestor(self): + roles = DeviceRole.objects.filter(parent__isnull=True)[:2] + params = {'ancestor_id': [roles[0].pk, roles[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'ancestor': [roles[0].slug, roles[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + class PlatformTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = Platform.objects.all() @@ -2259,7 +2498,8 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests): DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() platforms = ( Platform(name='Platform 1', slug='platform-1'), @@ -2924,7 +3164,8 @@ class ConsolePortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3136,7 +3377,8 @@ class ConsoleServerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeL DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3354,7 +3596,8 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3598,7 +3841,8 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3684,6 +3928,7 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A, description='First', color='ff0000', + status=PowerOutletStatusChoices.STATUS_ENABLED, ), PowerOutlet( device=devices[1], @@ -3693,6 +3938,7 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF feed_leg=PowerOutletFeedLegChoices.FEED_LEG_B, description='Second', color='00ff00', + status=PowerOutletStatusChoices.STATUS_DISABLED, ), PowerOutlet( device=devices[2], @@ -3702,6 +3948,7 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF feed_leg=PowerOutletFeedLegChoices.FEED_LEG_C, description='Third', color='0000ff', + status=PowerOutletStatusChoices.STATUS_FAULTY, ), ) PowerOutlet.objects.bulk_create(power_outlets) @@ -3796,6 +4043,23 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF params = {'connected': False} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_status(self): + params = {'status': [PowerOutletStatusChoices.STATUS_ENABLED]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'status': [PowerOutletStatusChoices.STATUS_DISABLED]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'status': [PowerOutletStatusChoices.STATUS_FAULTY]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'status': [ + PowerOutletStatusChoices.STATUS_ENABLED, + PowerOutletStatusChoices.STATUS_DISABLED, + PowerOutletStatusChoices.STATUS_FAULTY, + ]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) + class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = Interface.objects.all() @@ -3843,7 +4107,8 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -4422,7 +4687,8 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -4694,7 +4960,8 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -4934,7 +5201,8 @@ class ModuleBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -5106,7 +5374,8 @@ class DeviceBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -5241,7 +5510,8 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() regions = ( Region(name='Region 1', slug='region-1'), diff --git a/netbox/dcim/tests/test_forms.py b/netbox/dcim/tests/test_forms.py index 7a57bf3f0b9..0067acaaf72 100644 --- a/netbox/dcim/tests/test_forms.py +++ b/netbox/dcim/tests/test_forms.py @@ -1,8 +1,11 @@ from django.test import TestCase -from dcim.choices import DeviceFaceChoices, DeviceStatusChoices, InterfaceTypeChoices +from dcim.choices import ( + DeviceFaceChoices, DeviceStatusChoices, InterfaceTypeChoices, InterfaceModeChoices, PowerOutletStatusChoices +) from dcim.forms import * from dcim.models import * +from ipam.models import VLAN from utilities.testing import create_test_device from virtualization.models import Cluster, ClusterGroup, ClusterType @@ -11,6 +14,56 @@ def get_id(model, slug): return model.objects.get(slug=slug).id +class PowerOutletFormTestCase(TestCase): + @classmethod + def setUpTestData(cls): + cls.site = site = Site.objects.create(name='Site 1', slug='site-1') + cls.manufacturer = manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') + cls.role = role = DeviceRole.objects.create( + name='Device Role 1', slug='device-role-1', color='ff0000' + ) + cls.device_type = device_type = DeviceType.objects.create( + manufacturer=manufacturer, model='Device Type 1', slug='device-type-1', u_height=1 + ) + cls.rack = rack = Rack.objects.create(name='Rack 1', site=site) + cls.device = Device.objects.create( + name='Device 1', device_type=device_type, role=role, site=site, rack=rack, position=1 + ) + + def test_status_is_required(self): + form = PowerOutletForm(data={ + 'device': self.device, + 'module': None, + 'name': 'New Enabled Outlet', + }) + self.assertFalse(form.is_valid()) + self.assertIn('status', form.errors) + + def test_status_must_be_defined_choice(self): + form = PowerOutletForm(data={ + 'device': self.device, + 'module': None, + 'name': 'New Enabled Outlet', + 'status': 'this isn\'t a defined choice', + }) + self.assertFalse(form.is_valid()) + self.assertIn('status', form.errors) + self.assertTrue(form.errors['status'][-1].startswith('Select a valid choice.')) + + def test_status_recognizes_choices(self): + for index, choice in enumerate(PowerOutletStatusChoices.CHOICES): + form = PowerOutletForm(data={ + 'device': self.device, + 'module': None, + 'name': f'New Enabled Outlet {index + 1}', + 'status': choice[0], + }) + self.assertEqual({}, form.errors) + self.assertTrue(form.is_valid()) + instance = form.save() + self.assertEqual(instance.status, choice[0]) + + class DeviceTestCase(TestCase): @classmethod @@ -117,11 +170,23 @@ class DeviceTestCase(TestCase): self.assertIn('position', form.errors) -class LabelTestCase(TestCase): +class InterfaceTestCase(TestCase): @classmethod def setUpTestData(cls): cls.device = create_test_device('Device 1') + cls.vlans = ( + VLAN(name='VLAN 1', vid=1), + VLAN(name='VLAN 2', vid=2), + VLAN(name='VLAN 3', vid=3), + ) + VLAN.objects.bulk_create(cls.vlans) + cls.interface = Interface.objects.create( + device=cls.device, + name='Interface 1', + type=InterfaceTypeChoices.TYPE_1GE_GBIC, + mode=InterfaceModeChoices.MODE_TAGGED, + ) def test_interface_label_count_valid(self): """ @@ -151,3 +216,152 @@ class LabelTestCase(TestCase): self.assertFalse(form.is_valid()) self.assertIn('label', form.errors) + + def test_create_interface_mode_valid_data(self): + """ + Test that saving valid interface mode and tagged/untagged vlans works properly + """ + + # Validate access mode + data = { + 'device': self.device.pk, + 'name': 'ethernet1/1', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_ACCESS, + 'untagged_vlan': self.vlans[0].pk + } + form = InterfaceCreateForm(data) + + self.assertTrue(form.is_valid()) + + # Validate tagged vlans + data = { + 'device': self.device.pk, + 'name': 'ethernet1/2', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_TAGGED, + 'untagged_vlan': self.vlans[0].pk, + 'tagged_vlans': [self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceCreateForm(data) + self.assertTrue(form.is_valid()) + + # Validate tagged vlans + data = { + 'device': self.device.pk, + 'name': 'ethernet1/3', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_TAGGED_ALL, + 'untagged_vlan': self.vlans[0].pk, + } + form = InterfaceCreateForm(data) + self.assertTrue(form.is_valid()) + + def test_create_interface_mode_access_invalid_data(self): + """ + Test that saving invalid interface mode and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'ethernet1/4', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_ACCESS, + 'untagged_vlan': self.vlans[0].pk, + 'tagged_vlans': [self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceCreateForm(data) + + self.assertTrue(form.is_valid()) + self.assertIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) + + def test_edit_interface_mode_access_invalid_data(self): + """ + Test that saving invalid interface mode and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'Ethernet 1/5', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_ACCESS, + 'tagged_vlans': [self.vlans[0].pk, self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceForm(data, instance=self.interface) + + self.assertTrue(form.is_valid()) + self.assertIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) + + def test_create_interface_mode_tagged_all_invalid_data(self): + """ + Test that saving invalid interface mode and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'ethernet1/6', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_TAGGED_ALL, + 'tagged_vlans': [self.vlans[0].pk, self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceCreateForm(data) + + self.assertTrue(form.is_valid()) + self.assertIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) + + def test_edit_interface_mode_tagged_all_invalid_data(self): + """ + Test that saving invalid interface mode and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'Ethernet 1/7', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': InterfaceModeChoices.MODE_TAGGED_ALL, + 'tagged_vlans': [self.vlans[0].pk, self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceForm(data) + self.assertTrue(form.is_valid()) + self.assertIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) + + def test_create_interface_mode_routed_invalid_data(self): + """ + Test that saving invalid interface mode (routed) and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'ethernet1/6', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': None, + 'untagged_vlan': self.vlans[0].pk, + 'tagged_vlans': [self.vlans[0].pk, self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceCreateForm(data) + + self.assertTrue(form.is_valid()) + self.assertNotIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) + + def test_edit_interface_mode_routed_invalid_data(self): + """ + Test that saving invalid interface mode (routed) and tagged/untagged vlans works properly + """ + data = { + 'device': self.device.pk, + 'name': 'Ethernet 1/7', + 'type': InterfaceTypeChoices.TYPE_1GE_GBIC, + 'mode': None, + 'untagged_vlan': self.vlans[0].pk, + 'tagged_vlans': [self.vlans[0].pk, self.vlans[1].pk, self.vlans[2].pk] + } + form = InterfaceForm(data) + self.assertTrue(form.is_valid()) + self.assertNotIn('untagged_vlan', form.cleaned_data.keys()) + self.assertNotIn('tagged_vlans', form.cleaned_data.keys()) + self.assertNotIn('qinq_svlan', form.cleaned_data.keys()) diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index ff1eddd562e..66f52b1bfc9 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -346,7 +346,8 @@ class DeviceTestCase(TestCase): DeviceRole(name='Test Role 1', slug='test-role-1'), DeviceRole(name='Test Role 2', slug='test-role-2'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() # Create a CustomField with a default value & assign it to all component models cf1 = CustomField.objects.create(name='cf1', default='foo') @@ -465,7 +466,8 @@ class DeviceTestCase(TestCase): device=device, name='Power Outlet 1', power_port=powerport, - feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A + feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A, + status=PowerOutletStatusChoices.STATUS_ENABLED, ) self.assertEqual(poweroutlet.cf['cf1'], 'foo') diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index b8421788291..3c43d1834b8 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1,3 +1,4 @@ +import json from decimal import Decimal from zoneinfo import ZoneInfo @@ -25,8 +26,10 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase): # Create three Regions regions = ( - Region(name='Region 1', slug='region-1'), - Region(name='Region 2', slug='region-2'), + Region(name='Region 1', slug='region-1', comments=''), + Region( + name='Region 2', slug='region-2', comments="It's going to take a lot to drag me away from you" + ), Region(name='Region 3', slug='region-3'), ) for region in regions: @@ -40,13 +43,14 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase): 'parent': regions[2].pk, 'description': 'A new region', 'tags': [t.pk for t in tags], + 'comments': 'This comment is really exciting!', } cls.csv_data = ( - "name,slug,description", - "Region 4,region-4,Fourth region", - "Region 5,region-5,Fifth region", - "Region 6,region-6,Sixth region", + "name,slug,description,comments", + "Region 4,region-4,Fourth region,", + "Region 5,region-5,Fifth region,hi guys", + "Region 6,region-6,Sixth region,bye guys", ) cls.csv_update_data = ( @@ -58,6 +62,7 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase): cls.bulk_edit_data = { 'description': 'New description', + 'comments': 'This comment is super exciting!!!', } @@ -69,7 +74,7 @@ class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase): # Create three SiteGroups sitegroups = ( - SiteGroup(name='Site Group 1', slug='site-group-1'), + SiteGroup(name='Site Group 1', slug='site-group-1', comments='Still here'), SiteGroup(name='Site Group 2', slug='site-group-2'), SiteGroup(name='Site Group 3', slug='site-group-3'), ) @@ -84,24 +89,26 @@ class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase): 'parent': sitegroups[2].pk, 'description': 'A new site group', 'tags': [t.pk for t in tags], + 'comments': 'still here', } cls.csv_data = ( - "name,slug,description", - "Site Group 4,site-group-4,Fourth site group", - "Site Group 5,site-group-5,Fifth site group", - "Site Group 6,site-group-6,Sixth site group", + "name,slug,description,comments", + "Site Group 4,site-group-4,Fourth site group,", + "Site Group 5,site-group-5,Fifth site group,still hear", + "Site Group 6,site-group-6,Sixth site group," ) cls.csv_update_data = ( - "id,name,description", - f"{sitegroups[0].pk},Site Group 7,Fourth site group7", - f"{sitegroups[1].pk},Site Group 8,Fifth site group8", - f"{sitegroups[2].pk},Site Group 0,Sixth site group9", + "id,name,description,comments", + f"{sitegroups[0].pk},Site Group 7,Fourth site group7,", + f"{sitegroups[1].pk},Site Group 8,Fifth site group8,when will it end", + f"{sitegroups[2].pk},Site Group 0,Sixth site group9,", ) cls.bulk_edit_data = { 'description': 'New description', + 'comments': 'the end', } @@ -202,6 +209,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase): site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant, + comments='', ), Location( name='Location 2', @@ -209,6 +217,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase): site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant, + comments='First comment!', ), Location( name='Location 3', @@ -216,6 +225,7 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase): site=site, status=LocationStatusChoices.STATUS_ACTIVE, tenant=tenant, + comments='_This_ is a **bold comment**', ), ) for location in locations: @@ -232,24 +242,26 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase): 'tenant': tenant.pk, 'description': 'A new location', 'tags': [t.pk for t in tags], + 'comments': 'This comment is really boring', } cls.csv_data = ( - "site,tenant,name,slug,status,description", - "Site 1,Tenant 1,Location 4,location-4,planned,Fourth location", - "Site 1,Tenant 1,Location 5,location-5,planned,Fifth location", - "Site 1,Tenant 1,Location 6,location-6,planned,Sixth location", + "site,tenant,name,slug,status,description,comments", + "Site 1,Tenant 1,Location 4,location-4,planned,Fourth location,", + "Site 1,Tenant 1,Location 5,location-5,planned,Fifth location,", + "Site 1,Tenant 1,Location 6,location-6,planned,Sixth location,hi!", ) cls.csv_update_data = ( - "id,name,description", - f"{locations[0].pk},Location 7,Fourth location7", - f"{locations[1].pk},Location 8,Fifth location8", - f"{locations[2].pk},Location 0,Sixth location9", + "id,name,description,comments", + f"{locations[0].pk},Location 7,Fourth location7,Useful comment", + f"{locations[1].pk},Location 8,Fifth location8,unuseful comment", + f"{locations[2].pk},Location 0,Sixth location9,", ) cls.bulk_edit_data = { 'description': 'New description', + 'comments': 'This comment is also really boring', } @@ -1294,6 +1306,79 @@ front-ports: self.assertEqual(response.get('Content-Type'), 'text/csv; charset=utf-8') +class ModuleTypeProfileTestCase(ViewTestCases.OrganizationalObjectViewTestCase): + model = ModuleTypeProfile + + SCHEMAS = [ + { + "properties": { + "foo": { + "type": "string" + } + } + }, + { + "properties": { + "foo": { + "type": "integer" + } + } + }, + { + "properties": { + "foo": { + "type": "boolean" + } + } + }, + ] + + @classmethod + def setUpTestData(cls): + module_type_profiles = ( + ModuleTypeProfile( + name='Module Type Profile 1', + schema=cls.SCHEMAS[0] + ), + ModuleTypeProfile( + name='Module Type Profile 2', + schema=cls.SCHEMAS[1] + ), + ModuleTypeProfile( + name='Module Type Profile 3', + schema=cls.SCHEMAS[2] + ), + ) + ModuleTypeProfile.objects.bulk_create(module_type_profiles) + + tags = create_tags('Alpha', 'Bravo', 'Charlie') + + cls.form_data = { + 'name': 'Module Type Profile X', + 'description': 'A new profile', + 'schema': json.dumps(cls.SCHEMAS[0]), + 'tags': [t.pk for t in tags], + } + + cls.csv_data = ( + "name,schema", + f"Module Type Profile 4,{json.dumps(cls.SCHEMAS[0])}", + f"Module Type Profile 5,{json.dumps(cls.SCHEMAS[1])}", + f"Module Type Profile 6,{json.dumps(cls.SCHEMAS[2])}", + ) + + cls.csv_update_data = ( + "id,description", + f"{module_type_profiles[0].pk},New description", + f"{module_type_profiles[1].pk},New description", + f"{module_type_profiles[2].pk},New description", + ) + + cls.bulk_edit_data = { + 'description': 'New description', + } + + # # DeviceType components # @@ -1683,13 +1768,16 @@ class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase): @classmethod def setUpTestData(cls): - roles = ( + roles = [ DeviceRole(name='Device Role 1', slug='device-role-1'), DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), - ) - DeviceRole.objects.bulk_create(roles) + DeviceRole(name='Device Role 4', slug='device-role-4'), + ] + for role in roles: + role.save() + roles.append(DeviceRole.objects.create(name='Device Role 5', slug='device-role-5', parent=roles[3])) tags = create_tags('Alpha', 'Bravo', 'Charlie') cls.form_data = { @@ -1713,6 +1801,7 @@ class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase): f"{roles[0].pk},Device Role 7,New description7", f"{roles[1].pk},Device Role 8,New description8", f"{roles[2].pk},Device Role 9,New description9", + f"{roles[4].pk},Device Role 10,New description10", ) cls.bulk_edit_data = { @@ -1798,7 +1887,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase): DeviceRole(name='Device Role 1', slug='device-role-1'), DeviceRole(name='Device Role 2', slug='device-role-2'), ) - DeviceRole.objects.bulk_create(roles) + for role in roles: + role.save() platforms = ( Platform(name='Platform 1', slug='platform-1'), @@ -2513,6 +2603,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase): 'device': device.pk, 'name': 'Power Outlet X', 'type': PowerOutletTypeChoices.TYPE_IEC_C13, + 'status': PowerOutletStatusChoices.STATUS_ENABLED, 'power_port': powerports[1].pk, 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B, 'description': 'A power outlet', @@ -2523,6 +2614,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase): 'device': device.pk, 'name': 'Power Outlet [4-6]', 'type': PowerOutletTypeChoices.TYPE_IEC_C13, + 'status': PowerOutletStatusChoices.STATUS_ENABLED, 'power_port': powerports[1].pk, 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B, 'description': 'A power outlet', @@ -2531,6 +2623,7 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase): cls.bulk_edit_data = { 'type': PowerOutletTypeChoices.TYPE_IEC_C15, + 'status': PowerOutletStatusChoices.STATUS_ENABLED, 'power_port': powerports[1].pk, 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B, 'description': 'New description', diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index bcfd327072e..1225938346d 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -37,6 +37,9 @@ urlpatterns = [ path('device-types/', include(get_model_urls('dcim', 'devicetype', detail=False))), path('device-types//', include(get_model_urls('dcim', 'devicetype'))), + path('module-type-profiles/', include(get_model_urls('dcim', 'moduletypeprofile', detail=False))), + path('module-type-profiles//', include(get_model_urls('dcim', 'moduletypeprofile'))), + path('module-types/', include(get_model_urls('dcim', 'moduletype', detail=False))), path('module-types//', include(get_model_urls('dcim', 'moduletype'))), diff --git a/netbox/dcim/utils.py b/netbox/dcim/utils.py index 4d42284908c..0931761bf02 100644 --- a/netbox/dcim/utils.py +++ b/netbox/dcim/utils.py @@ -1,3 +1,4 @@ +from django.apps import apps from django.contrib.contenttypes.models import ContentType from django.db import transaction @@ -56,3 +57,22 @@ def rebuild_paths(terminations): for cp in cable_paths: cp.delete() create_cablepath(cp.origins) + + +def update_interface_bridges(device, interface_templates, module=None): + """ + Used for device and module instantiation. Iterates all InterfaceTemplates with a bridge assigned + and applies it to the actual interfaces. + """ + Interface = apps.get_model('dcim', 'Interface') + + for interface_template in interface_templates.exclude(bridge=None): + interface = Interface.objects.get(device=device, name=interface_template.resolve_name(module=module)) + + if interface_template.bridge: + interface.bridge = Interface.objects.get( + device=device, + name=interface_template.bridge.resolve_name(module=module) + ) + interface.full_clean() + interface.save() diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 0978747d1ba..1e231ae3a00 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -4,7 +4,6 @@ from django.core.paginator import EmptyPage, PageNotAnInteger from django.db import transaction from django.db.models import Prefetch from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory -from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.html import escape @@ -19,7 +18,6 @@ from ipam.models import ASN, IPAddress, Prefix, VLANGroup from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable from netbox.constants import DEFAULT_ACTION_PERMISSIONS from netbox.views import generic -from tenancy.views import ObjectContactsView from utilities.forms import ConfirmationForm from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.permissions import get_permission_for_model @@ -304,11 +302,6 @@ class RegionBulkDeleteView(generic.BulkDeleteView): table = tables.RegionTable -@register_model_view(Region, 'contacts') -class RegionContactsView(ObjectContactsView): - queryset = Region.objects.all() - - # # Site groups # @@ -412,11 +405,6 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView): table = tables.SiteGroupTable -@register_model_view(SiteGroup, 'contacts') -class SiteGroupContactsView(ObjectContactsView): - queryset = SiteGroup.objects.all() - - # # Sites # @@ -494,11 +482,6 @@ class SiteBulkDeleteView(generic.BulkDeleteView): table = tables.SiteTable -@register_model_view(Site, 'contacts') -class SiteContactsView(ObjectContactsView): - queryset = Site.objects.all() - - # # Locations # @@ -596,11 +579,6 @@ class LocationBulkDeleteView(generic.BulkDeleteView): table = tables.LocationTable -@register_model_view(Location, 'contacts') -class LocationContactsView(ObjectContactsView): - queryset = Location.objects.all() - - # # Rack roles # @@ -887,11 +865,6 @@ class RackBulkDeleteView(generic.BulkDeleteView): table = tables.RackTable -@register_model_view(Rack, 'contacts') -class RackContactsView(ObjectContactsView): - queryset = Rack.objects.all() - - # # Rack reservations # @@ -1029,11 +1002,6 @@ class ManufacturerBulkDeleteView(generic.BulkDeleteView): table = tables.ManufacturerTable -@register_model_view(Manufacturer, 'contacts') -class ManufacturerContactsView(ObjectContactsView): - queryset = Manufacturer.objects.all() - - # # Device types # @@ -1278,6 +1246,62 @@ class DeviceTypeBulkDeleteView(generic.BulkDeleteView): table = tables.DeviceTypeTable +# +# Module type profiles +# + +@register_model_view(ModuleTypeProfile, 'list', path='', detail=False) +class ModuleTypeProfileListView(generic.ObjectListView): + queryset = ModuleTypeProfile.objects.annotate( + instance_count=count_related(ModuleType, 'profile') + ) + filterset = filtersets.ModuleTypeProfileFilterSet + filterset_form = forms.ModuleTypeProfileFilterForm + table = tables.ModuleTypeProfileTable + + +@register_model_view(ModuleTypeProfile) +class ModuleTypeProfileView(GetRelatedModelsMixin, generic.ObjectView): + queryset = ModuleTypeProfile.objects.all() + + +@register_model_view(ModuleTypeProfile, 'add', detail=False) +@register_model_view(ModuleTypeProfile, 'edit') +class ModuleTypeProfileEditView(generic.ObjectEditView): + queryset = ModuleTypeProfile.objects.all() + form = forms.ModuleTypeProfileForm + + +@register_model_view(ModuleTypeProfile, 'delete') +class ModuleTypeProfileDeleteView(generic.ObjectDeleteView): + queryset = ModuleTypeProfile.objects.all() + + +@register_model_view(ModuleTypeProfile, 'bulk_import', detail=False) +class ModuleTypeProfileBulkImportView(generic.BulkImportView): + queryset = ModuleTypeProfile.objects.all() + model_form = forms.ModuleTypeProfileImportForm + + +@register_model_view(ModuleTypeProfile, 'bulk_edit', path='edit', detail=False) +class ModuleTypeProfileBulkEditView(generic.BulkEditView): + queryset = ModuleTypeProfile.objects.annotate( + instance_count=count_related(Module, 'module_type') + ) + filterset = filtersets.ModuleTypeProfileFilterSet + table = tables.ModuleTypeProfileTable + form = forms.ModuleTypeProfileBulkEditForm + + +@register_model_view(ModuleTypeProfile, 'bulk_delete', path='delete', detail=False) +class ModuleTypeProfileBulkDeleteView(generic.BulkDeleteView): + queryset = ModuleTypeProfile.objects.annotate( + instance_count=count_related(Module, 'module_type') + ) + filterset = filtersets.ModuleTypeProfileFilterSet + table = tables.ModuleTypeProfileTable + + # # Module types # @@ -2268,10 +2292,7 @@ class DeviceRenderConfigView(generic.ObjectView): # If a direct export has been requested, return the rendered template content as a # downloadable file. if request.GET.get('export'): - content = context['rendered_config'] or context['error_message'] - response = HttpResponse(content, content_type='text') - filename = f"{instance.name or 'config'}.txt" - response['Content-Disposition'] = f'attachment; filename="{filename}"' + response = context['config_template'].render_to_response(context=context['context_data']) return response return render(request, self.get_template_name(), { @@ -2360,11 +2381,6 @@ class DeviceBulkRenameView(generic.BulkRenameView): table = tables.DeviceTable -@register_model_view(Device, 'contacts') -class DeviceContactsView(ObjectContactsView): - queryset = Device.objects.all() - - # # Modules # @@ -3924,11 +3940,6 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView): table = tables.PowerPanelTable -@register_model_view(PowerPanel, 'contacts') -class PowerPanelContactsView(ObjectContactsView): - queryset = PowerPanel.objects.all() - - # # Power feeds # diff --git a/netbox/extras/api/serializers_/configtemplates.py b/netbox/extras/api/serializers_/configtemplates.py index c4a683c742f..69652907e96 100644 --- a/netbox/extras/api/serializers_/configtemplates.py +++ b/netbox/extras/api/serializers_/configtemplates.py @@ -22,6 +22,7 @@ class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer model = ConfigTemplate fields = [ 'id', 'url', 'display_url', 'display', 'name', 'description', 'environment_params', 'template_code', - 'data_source', 'data_path', 'data_file', 'data_synced', 'tags', 'created', 'last_updated', + 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', + 'data_synced', 'tags', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'name', 'description') diff --git a/netbox/extras/api/serializers_/exporttemplates.py b/netbox/extras/api/serializers_/exporttemplates.py index 11f502a02b9..0d19d642cf5 100644 --- a/netbox/extras/api/serializers_/exporttemplates.py +++ b/netbox/extras/api/serializers_/exporttemplates.py @@ -26,8 +26,8 @@ class ExportTemplateSerializer(ValidatedModelSerializer): class Meta: model = ExportTemplate fields = [ - 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'template_code', 'mime_type', - 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'data_synced', 'created', - 'last_updated', + 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'environment_params', + 'template_code', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', + 'data_path', 'data_file', 'data_synced', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'name', 'description') diff --git a/netbox/extras/api/serializers_/tags.py b/netbox/extras/api/serializers_/tags.py index e4e62845a83..5dc39584f54 100644 --- a/netbox/extras/api/serializers_/tags.py +++ b/netbox/extras/api/serializers_/tags.py @@ -1,10 +1,16 @@ +from drf_spectacular.utils import extend_schema_field +from rest_framework import serializers + from core.models import ObjectType -from extras.models import Tag +from extras.models import Tag, TaggedItem +from netbox.api.exceptions import SerializerNotFound from netbox.api.fields import ContentTypeField, RelatedObjectCountField -from netbox.api.serializers import ValidatedModelSerializer +from netbox.api.serializers import BaseModelSerializer, ValidatedModelSerializer +from utilities.api import get_serializer_for_model __all__ = ( 'TagSerializer', + 'TaggedItemSerializer', ) @@ -21,7 +27,41 @@ class TagSerializer(ValidatedModelSerializer): class Meta: model = Tag fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'object_types', - 'tagged_items', 'created', 'last_updated', + 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'weight', + 'object_types', 'tagged_items', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'color', 'description') + + +class TaggedItemSerializer(BaseModelSerializer): + object_type = ContentTypeField( + source='content_type', + read_only=True + ) + object = serializers.SerializerMethodField( + read_only=True + ) + tag = TagSerializer( + nested=True, + read_only=True + ) + + class Meta: + model = TaggedItem + fields = [ + 'id', 'url', 'display', 'object_type', 'object_id', 'object', 'tag', + ] + brief_fields = ('id', 'url', 'display', 'object_type', 'object_id', 'object', 'tag') + + @extend_schema_field(serializers.JSONField()) + def get_object(self, obj): + """ + Serialize a nested representation of the tagged object. + """ + try: + serializer = get_serializer_for_model(obj.content_object) + except SerializerNotFound: + return obj.object_repr + data = serializer(obj.content_object, nested=True, context={'request': self.context['request']}).data + + return data diff --git a/netbox/extras/api/urls.py b/netbox/extras/api/urls.py index bbcb8f0ef2b..88121b6401a 100644 --- a/netbox/extras/api/urls.py +++ b/netbox/extras/api/urls.py @@ -19,6 +19,7 @@ router.register('notifications', views.NotificationViewSet) router.register('notification-groups', views.NotificationGroupViewSet) router.register('subscriptions', views.SubscriptionViewSet) router.register('tags', views.TagViewSet) +router.register('tagged-objects', views.TaggedItemViewSet) router.register('image-attachments', views.ImageAttachmentViewSet) router.register('journal-entries', views.JournalEntryViewSet) router.register('config-contexts', views.ConfigContextViewSet) diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index e4c3c7f3e0e..49a44f5f109 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -6,6 +6,7 @@ from rest_framework import status from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied from rest_framework.generics import RetrieveUpdateDestroyAPIView +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.renderers import JSONRenderer from rest_framework.response import Response from rest_framework.routers import APIRootView @@ -20,7 +21,7 @@ from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired from netbox.api.features import SyncedDataMixin from netbox.api.metadata import ContentTypeMetadata from netbox.api.renderers import TextRenderer -from netbox.api.viewsets import NetBoxModelViewSet +from netbox.api.viewsets import BaseViewSet, NetBoxModelViewSet from utilities.exceptions import RQWorkerNotRunningException from utilities.request import copy_safe_request from . import serializers @@ -172,6 +173,12 @@ class TagViewSet(NetBoxModelViewSet): filterset_class = filtersets.TagFilterSet +class TaggedItemViewSet(RetrieveModelMixin, ListModelMixin, BaseViewSet): + queryset = TaggedItem.objects.prefetch_related('content_type', 'content_object', 'tag') + serializer_class = serializers.TaggedItemSerializer + filterset_class = filtersets.TaggedItemFilterSet + + # # Image attachments # diff --git a/netbox/extras/choices.py b/netbox/extras/choices.py index 4525d86891c..3ecc7e57f3d 100644 --- a/netbox/extras/choices.py +++ b/netbox/extras/choices.py @@ -212,23 +212,6 @@ class WebhookHttpMethodChoices(ChoiceSet): ) -# -# Staging -# - -class ChangeActionChoices(ChoiceSet): - - ACTION_CREATE = 'create' - ACTION_UPDATE = 'update' - ACTION_DELETE = 'delete' - - CHOICES = ( - (ACTION_CREATE, _('Create'), 'green'), - (ACTION_UPDATE, _('Update'), 'blue'), - (ACTION_DELETE, _('Delete'), 'red'), - ) - - # # Dashboard widgets # diff --git a/netbox/extras/constants.py b/netbox/extras/constants.py index 123b771f6a2..db378c8faaf 100644 --- a/netbox/extras/constants.py +++ b/netbox/extras/constants.py @@ -4,6 +4,9 @@ from extras.choices import LogLevelChoices # Custom fields CUSTOMFIELD_EMPTY_VALUES = (None, '', []) +# Template Export +DEFAULT_MIME_TYPE = 'text/plain; charset=utf-8' + # Webhooks HTTP_CONTENT_TYPE_JSON = 'application/json' diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index eeed5414f86..c04f8f423ba 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -17,6 +17,7 @@ from core.models import ObjectType from extras.choices import BookmarkOrderingChoices from utilities.object_types import object_type_identifier, object_type_name from utilities.permissions import get_permission_for_model +from utilities.proxy import resolve_proxies from utilities.querydict import dict_to_querydict from utilities.templatetags.builtins.filters import render_markdown from utilities.views import get_viewname @@ -330,7 +331,7 @@ class RSSFeedWidget(DashboardWidget): response = requests.get( url=self.config['feed_url'], headers={'User-Agent': f'NetBox/{settings.RELEASE.version}'}, - proxies=settings.HTTP_PROXIES, + proxies=resolve_proxies(url=self.config['feed_url'], context={'client': self}), timeout=3 ) response.raise_for_status() diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 4f40ce50017..89dd4c9f1af 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -8,7 +8,9 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet from tenancy.models import Tenant, TenantGroup from users.models import Group, User -from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter +from utilities.filters import ( + ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter +) from virtualization.models import Cluster, ClusterGroup, ClusterType from .choices import * from .filters import TagFilter @@ -31,6 +33,7 @@ __all__ = ( 'SavedFilterFilterSet', 'ScriptFilterSet', 'TagFilterSet', + 'TaggedItemFilterSet', 'WebhookFilterSet', ) @@ -257,8 +260,8 @@ class ExportTemplateFilterSet(ChangeLoggedModelFilterSet): class Meta: model = ExportTemplate fields = ( - 'id', 'name', 'description', 'mime_type', 'file_extension', 'as_attachment', 'auto_sync_enabled', - 'data_synced', + 'id', 'name', 'description', 'mime_type', 'file_name', 'file_extension', 'as_attachment', + 'auto_sync_enabled', 'data_synced', ) def search(self, queryset, name, value): @@ -266,7 +269,8 @@ class ExportTemplateFilterSet(ChangeLoggedModelFilterSet): return queryset return queryset.filter( Q(name__icontains=value) | - Q(description__icontains=value) + Q(description__icontains=value) | + Q(file_name__icontains=value) ) @@ -449,7 +453,7 @@ class TagFilterSet(ChangeLoggedModelFilterSet): class Meta: model = Tag - fields = ('id', 'name', 'slug', 'color', 'description', 'object_types') + fields = ('id', 'name', 'slug', 'color', 'weight', 'description', 'object_types') def search(self, queryset, name, value): if not value.strip(): @@ -492,6 +496,41 @@ class TagFilterSet(ChangeLoggedModelFilterSet): ) +class TaggedItemFilterSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label=_('Search'), + ) + object_type = ContentTypeFilter( + field_name='content_type' + ) + object_type_id = django_filters.ModelMultipleChoiceFilter( + queryset=ContentType.objects.all(), + field_name='content_type_id' + ) + tag_id = django_filters.ModelMultipleChoiceFilter( + queryset=Tag.objects.all() + ) + tag = django_filters.ModelMultipleChoiceFilter( + field_name='tag__slug', + queryset=Tag.objects.all(), + to_field_name='slug', + ) + + class Meta: + model = TaggedItem + fields = ('id', 'object_id') + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(tag__name__icontains=value) | + Q(tag__slug__icontains=value) | + Q(tag__description__icontains=value) + ) + + class ConfigContextFilterSet(ChangeLoggedModelFilterSet): q = django_filters.CharFilter( method='search', @@ -668,7 +707,10 @@ class ConfigTemplateFilterSet(ChangeLoggedModelFilterSet): class Meta: model = ConfigTemplate - fields = ('id', 'name', 'description', 'auto_sync_enabled', 'data_synced') + fields = ( + 'id', 'name', 'description', 'mime_type', 'file_name', 'file_extension', 'as_attachment', + 'auto_sync_enabled', 'data_synced' + ) def search(self, queryset, name, value): if not value.strip(): diff --git a/netbox/extras/forms/bulk_edit.py b/netbox/extras/forms/bulk_edit.py index 30d06683b83..7a78dba8b44 100644 --- a/netbox/extras/forms/bulk_edit.py +++ b/netbox/extras/forms/bulk_edit.py @@ -155,6 +155,10 @@ class ExportTemplateBulkEditForm(BulkEditForm): max_length=50, required=False ) + file_name = forms.CharField( + label=_('File name'), + required=False + ) file_extension = forms.CharField( label=_('File extension'), max_length=15, @@ -166,7 +170,7 @@ class ExportTemplateBulkEditForm(BulkEditForm): widget=BulkEditNullBooleanSelect() ) - nullable_fields = ('description', 'mime_type', 'file_extension') + nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension') class SavedFilterBulkEditForm(BulkEditForm): @@ -275,6 +279,10 @@ class TagBulkEditForm(BulkEditForm): max_length=200, required=False ) + weight = forms.IntegerField( + label=_('Weight'), + required=False + ) nullable_fields = ('description',) @@ -313,8 +321,27 @@ class ConfigTemplateBulkEditForm(BulkEditForm): max_length=200, required=False ) + mime_type = forms.CharField( + label=_('MIME type'), + max_length=50, + required=False + ) + file_name = forms.CharField( + label=_('File name'), + required=False + ) + file_extension = forms.CharField( + label=_('File extension'), + max_length=15, + required=False + ) + as_attachment = forms.NullBooleanField( + label=_('As attachment'), + required=False, + widget=BulkEditNullBooleanSelect() + ) - nullable_fields = ('description',) + nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension') class JournalEntryBulkEditForm(BulkEditForm): diff --git a/netbox/extras/forms/bulk_import.py b/netbox/extras/forms/bulk_import.py index 655a5d6ca26..7c270da4a6e 100644 --- a/netbox/extras/forms/bulk_import.py +++ b/netbox/extras/forms/bulk_import.py @@ -144,7 +144,8 @@ class ExportTemplateImportForm(CSVModelForm): class Meta: model = ExportTemplate fields = ( - 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'template_code', + 'name', 'object_types', 'description', 'environment_params', 'mime_type', 'file_name', 'file_extension', + 'as_attachment', 'template_code', ) @@ -153,7 +154,8 @@ class ConfigTemplateImportForm(CSVModelForm): class Meta: model = ConfigTemplate fields = ( - 'name', 'description', 'environment_params', 'template_code', 'tags', + 'name', 'description', 'template_code', 'environment_params', 'mime_type', 'file_name', 'file_extension', + 'as_attachment', 'tags', ) @@ -232,10 +234,14 @@ class EventRuleImportForm(NetBoxModelImportForm): class TagImportForm(CSVModelForm): slug = SlugField() + weight = forms.IntegerField( + label=_('Weight'), + required=False + ) class Meta: model = Tag - fields = ('name', 'slug', 'color', 'description') + fields = ('name', 'slug', 'color', 'weight', 'description') class JournalEntryImportForm(NetBoxModelImportForm): diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 05dcf96c476..056ca62a567 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -160,9 +160,9 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( - FieldSet('q', 'filter_id'), + FieldSet('q', 'filter_id', 'object_type_id'), FieldSet('data_source_id', 'data_file_id', name=_('Data')), - FieldSet('object_type_id', 'mime_type', 'file_extension', 'as_attachment', name=_('Attributes')), + FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -186,6 +186,10 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): required=False, label=_('MIME type') ) + file_name = forms.CharField( + label=_('File name'), + required=False + ) file_extension = forms.CharField( label=_('File extension'), required=False @@ -318,7 +322,7 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): FieldSet('q', 'filter_id', 'tag_id'), FieldSet('data_source_id', 'data_file_id', name=_('Data')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), - FieldSet('device_type_id', 'platform_id', 'role_id', name=_('Device')), + FieldSet('device_type_id', 'platform_id', 'device_role_id', name=_('Device')), FieldSet('cluster_type_id', 'cluster_group_id', 'cluster_id', name=_('Cluster')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')) ) @@ -360,7 +364,7 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): required=False, label=_('Device types') ) - role_id = DynamicModelMultipleChoiceField( + device_role_id = DynamicModelMultipleChoiceField( queryset=DeviceRole.objects.all(), required=False, label=_('Roles') @@ -406,6 +410,7 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( FieldSet('q', 'filter_id', 'tag'), FieldSet('data_source_id', 'data_file_id', name=_('Data')), + FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')) ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -421,6 +426,25 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): } ) tag = TagFilterField(ConfigTemplate) + mime_type = forms.CharField( + required=False, + label=_('MIME type') + ) + file_name = forms.CharField( + label=_('File name'), + required=False + ) + file_extension = forms.CharField( + label=_('File extension'), + required=False + ) + as_attachment = forms.NullBooleanField( + label=_('As attachment'), + required=False, + widget=forms.Select( + choices=BOOLEAN_WITH_BLANK_CHOICES + ) + ) class LocalConfigContextFilterForm(forms.Form): diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index a45daaf7084..594b7d9d014 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -246,7 +246,9 @@ class ExportTemplateForm(SyncedDataMixin, forms.ModelForm): fieldsets = ( FieldSet('name', 'object_types', 'description', 'template_code', name=_('Export Template')), FieldSet('data_source', 'data_file', 'auto_sync_enabled', name=_('Data Source')), - FieldSet('mime_type', 'file_extension', 'as_attachment', name=_('Rendering')), + FieldSet( + 'mime_type', 'file_name', 'file_extension', 'environment_params', 'as_attachment', name=_('Rendering') + ), ) class Meta: @@ -490,15 +492,19 @@ class TagForm(forms.ModelForm): queryset=ObjectType.objects.with_feature('tags'), required=False ) + weight = forms.IntegerField( + label=_('Weight'), + required=False + ) fieldsets = ( - FieldSet('name', 'slug', 'color', 'description', 'object_types', name=_('Tag')), + FieldSet('name', 'slug', 'color', 'weight', 'description', 'object_types', name=_('Tag')), ) class Meta: model = Tag fields = [ - 'name', 'slug', 'color', 'description', 'object_types', + 'name', 'slug', 'color', 'weight', 'description', 'object_types', ] @@ -627,9 +633,11 @@ class ConfigTemplateForm(SyncedDataMixin, forms.ModelForm): ) fieldsets = ( - FieldSet('name', 'description', 'environment_params', 'tags', name=_('Config Template')), - FieldSet('template_code', name=_('Content')), + FieldSet('name', 'description', 'tags', 'template_code', name=_('Config Template')), FieldSet('data_source', 'data_file', 'auto_sync_enabled', name=_('Data Source')), + FieldSet( + 'mime_type', 'file_name', 'file_extension', 'environment_params', 'as_attachment', name=_('Rendering') + ), ) class Meta: diff --git a/netbox/extras/forms/scripts.py b/netbox/extras/forms/scripts.py index 331f7f01f96..764246a2d1b 100644 --- a/netbox/extras/forms/scripts.py +++ b/netbox/extras/forms/scripts.py @@ -1,11 +1,18 @@ +import os + from django import forms +from django.conf import settings +from django.core.files.storage import storages from django.utils.translation import gettext_lazy as _ +from core.forms import ManagedFileForm from extras.choices import DurationChoices +from extras.storage import ScriptFileSystemStorage from utilities.forms.widgets import DateTimePicker, NumberWithOptions from utilities.datetime import local_now __all__ = ( + 'ScriptFileForm', 'ScriptForm', ) @@ -55,3 +62,26 @@ class ScriptForm(forms.Form): self.cleaned_data['_schedule_at'] = local_now() return self.cleaned_data + + +class ScriptFileForm(ManagedFileForm): + """ + ManagedFileForm with a custom save method to use django-storages. + """ + def save(self, *args, **kwargs): + # If a file was uploaded, save it to disk + if self.cleaned_data['upload_file']: + storage = storages.create_storage(storages.backends["scripts"]) + + filename = self.cleaned_data['upload_file'].name + if isinstance(storage, ScriptFileSystemStorage): + full_path = os.path.join(settings.SCRIPTS_ROOT, filename) + else: + full_path = filename + + self.instance.file_path = full_path + data = self.cleaned_data['upload_file'] + storage.save(filename, data) + + # need to skip ManagedFileForm save method + return super(ManagedFileForm, self).save(*args, **kwargs) diff --git a/netbox/extras/graphql/enums.py b/netbox/extras/graphql/enums.py new file mode 100644 index 00000000000..0d352b835f6 --- /dev/null +++ b/netbox/extras/graphql/enums.py @@ -0,0 +1,26 @@ +import strawberry + +from extras.choices import * + +__all__ = ( + 'CustomFieldChoiceSetBaseEnum', + 'CustomFieldFilterLogicEnum', + 'CustomFieldTypeEnum', + 'CustomFieldUIEditableEnum', + 'CustomFieldUIVisibleEnum', + 'CustomLinkButtonClassEnum', + 'EventRuleActionEnum', + 'JournalEntryKindEnum', + 'WebhookHttpMethodEnum', +) + + +CustomFieldChoiceSetBaseEnum = strawberry.enum(CustomFieldChoiceSetBaseChoices.as_enum()) +CustomFieldFilterLogicEnum = strawberry.enum(CustomFieldFilterLogicChoices.as_enum()) +CustomFieldTypeEnum = strawberry.enum(CustomFieldTypeChoices.as_enum()) +CustomFieldUIEditableEnum = strawberry.enum(CustomFieldUIEditableChoices.as_enum()) +CustomFieldUIVisibleEnum = strawberry.enum(CustomFieldUIVisibleChoices.as_enum()) +CustomLinkButtonClassEnum = strawberry.enum(CustomLinkButtonClassChoices.as_enum()) +EventRuleActionEnum = strawberry.enum(EventRuleActionChoices.as_enum()) +JournalEntryKindEnum = strawberry.enum(JournalEntryKindChoices.as_enum()) +WebhookHttpMethodEnum = strawberry.enum(WebhookHttpMethodChoices.as_enum()) diff --git a/netbox/extras/graphql/filter_mixins.py b/netbox/extras/graphql/filter_mixins.py new file mode 100644 index 00000000000..7e9a970f26e --- /dev/null +++ b/netbox/extras/graphql/filter_mixins.py @@ -0,0 +1,52 @@ +from dataclasses import dataclass +from typing import Annotated, TYPE_CHECKING + +import strawberry +import strawberry_django +from strawberry_django import FilterLookup + +from core.graphql.filter_mixins import BaseFilterMixin + +if TYPE_CHECKING: + from netbox.graphql.filter_lookups import JSONFilter + from .filters import * + +__all__ = ( + 'CustomFieldsFilterMixin', + 'JournalEntriesFilterMixin', + 'TagsFilterMixin', + 'ConfigContextFilterMixin', + 'TagBaseFilterMixin', +) + + +@dataclass +class CustomFieldsFilterMixin(BaseFilterMixin): + custom_field_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class JournalEntriesFilterMixin(BaseFilterMixin): + journal_entries: Annotated['JournalEntryFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class TagsFilterMixin(BaseFilterMixin): + tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field() + + +@dataclass +class ConfigContextFilterMixin(BaseFilterMixin): + local_context_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class TagBaseFilterMixin(BaseFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/extras/graphql/filters.py b/netbox/extras/graphql/filters.py index ff2e6a0f177..b8db143e43a 100644 --- a/netbox/extras/graphql/filters.py +++ b/netbox/extras/graphql/filters.py @@ -1,7 +1,26 @@ -import strawberry_django +from typing import Annotated, TYPE_CHECKING -from extras import filtersets, models -from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin +import strawberry +import strawberry_django +from strawberry.scalars import ID +from strawberry_django import FilterLookup + +from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin +from extras import models +from extras.graphql.filter_mixins import TagBaseFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin +from netbox.graphql.filter_mixins import SyncedDataFilterMixin + +if TYPE_CHECKING: + from core.graphql.filters import ContentTypeFilter + from dcim.graphql.filters import ( + DeviceRoleFilter, DeviceTypeFilter, LocationFilter, PlatformFilter, RegionFilter, SiteFilter, SiteGroupFilter, + ) + from tenancy.graphql.filters import TenantFilter, TenantGroupFilter + from netbox.graphql.enums import ColorEnum + from netbox.graphql.filter_lookups import IntegerLookup, JSONFilter, StringArrayLookup, TreeNodeFilter + from users.graphql.filters import GroupFilter, UserFilter + from virtualization.graphql.filters import ClusterFilter, ClusterGroupFilter, ClusterTypeFilter + from .enums import * __all__ = ( 'ConfigContextFilter', @@ -21,78 +40,271 @@ __all__ = ( @strawberry_django.filter(models.ConfigContext, lookups=True) -@autotype_decorator(filtersets.ConfigContextFilterSet) -class ConfigContextFilter(BaseFilterMixin): - pass +class ConfigContextFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] = strawberry_django.filter_field() + weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + description: FilterLookup[str] = strawberry_django.filter_field() + is_active: FilterLookup[bool] = strawberry_django.filter_field() + regions: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + region_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + site_groups: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + site_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + sites: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + locations: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + device_types: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + roles: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + platforms: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + cluster_types: Annotated['ClusterTypeFilter', strawberry.lazy('virtualization.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + cluster_groups: Annotated['ClusterGroupFilter', strawberry.lazy('virtualization.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + clusters: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + tenant_groups: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + tenant_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + tenants: Annotated['TenantFilter', strawberry.lazy('tenancy.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field() + data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ConfigTemplate, lookups=True) -@autotype_decorator(filtersets.ConfigTemplateFilterSet) -class ConfigTemplateFilter(BaseFilterMixin): - pass +class ConfigTemplateFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + template_code: FilterLookup[str] | None = strawberry_django.filter_field() + environment_params: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + mime_type: FilterLookup[str] | None = strawberry_django.filter_field() + file_name: FilterLookup[str] | None = strawberry_django.filter_field() + file_extension: FilterLookup[str] | None = strawberry_django.filter_field() + as_attachment: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.CustomField, lookups=True) -@autotype_decorator(filtersets.CustomFieldFilterSet) -class CustomFieldFilter(BaseFilterMixin): - pass +class CustomFieldFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + type: Annotated['CustomFieldTypeEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + object_types: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + related_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() + label: FilterLookup[str] | None = strawberry_django.filter_field() + group_name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + required: FilterLookup[bool] | None = strawberry_django.filter_field() + unique: FilterLookup[bool] | None = strawberry_django.filter_field() + search_weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + filter_logic: Annotated['CustomFieldFilterLogicEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + default: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + related_object_filter: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + validation_minimum: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + validation_maximum: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + validation_regex: FilterLookup[str] | None = strawberry_django.filter_field() + choice_set: Annotated['CustomFieldChoiceSetFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + choice_set_id: ID | None = strawberry_django.filter_field() + ui_visible: Annotated['CustomFieldUIVisibleEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + ui_editable: Annotated['CustomFieldUIEditableEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + is_cloneable: FilterLookup[bool] | None = strawberry_django.filter_field() + comments: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.CustomFieldChoiceSet, lookups=True) -@autotype_decorator(filtersets.CustomFieldChoiceSetFilterSet) -class CustomFieldChoiceSetFilter(BaseFilterMixin): - pass +class CustomFieldChoiceSetFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + base_choices: Annotated['CustomFieldChoiceSetBaseEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + extra_choices: Annotated['StringArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + order_alphabetically: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.CustomLink, lookups=True) -@autotype_decorator(filtersets.CustomLinkFilterSet) -class CustomLinkFilter(BaseFilterMixin): - pass +class CustomLinkFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + link_text: FilterLookup[str] | None = strawberry_django.filter_field() + link_url: FilterLookup[str] | None = strawberry_django.filter_field() + weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + group_name: FilterLookup[str] | None = strawberry_django.filter_field() + button_class: Annotated['CustomLinkButtonClassEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + new_window: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ExportTemplate, lookups=True) -@autotype_decorator(filtersets.ExportTemplateFilterSet) -class ExportTemplateFilter(BaseFilterMixin): - pass +class ExportTemplateFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + template_code: FilterLookup[str] | None = strawberry_django.filter_field() + environment_params: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + mime_type: FilterLookup[str] | None = strawberry_django.filter_field() + file_name: FilterLookup[str] | None = strawberry_django.filter_field() + file_extension: FilterLookup[str] | None = strawberry_django.filter_field() + as_attachment: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.ImageAttachment, lookups=True) -@autotype_decorator(filtersets.ImageAttachmentFilterSet) -class ImageAttachmentFilter(BaseFilterMixin): - pass +class ImageAttachmentFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + object_id: ID | None = strawberry_django.filter_field() + image_height: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + image_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.JournalEntry, lookups=True) -@autotype_decorator(filtersets.JournalEntryFilterSet) -class JournalEntryFilter(BaseFilterMixin): - pass +class JournalEntryFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin): + assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + assigned_object_type_id: ID | None = strawberry_django.filter_field() + assigned_object_id: ID | None = strawberry_django.filter_field() + created_by: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + kind: Annotated['JournalEntryKindEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + comments: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.NotificationGroup, lookups=True) -@autotype_decorator(filtersets.NotificationGroupFilterSet) -class NotificationGroupFilter(BaseFilterMixin): - pass +class NotificationGroupFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + users: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() @strawberry_django.filter(models.SavedFilter, lookups=True) -@autotype_decorator(filtersets.SavedFilterFilterSet) -class SavedFilterFilter(BaseFilterMixin): - pass +class SavedFilterFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + user_id: ID | None = strawberry_django.filter_field() + weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + shared: FilterLookup[bool] | None = strawberry_django.filter_field() + parameters: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Tag, lookups=True) -@autotype_decorator(filtersets.TagFilterSet) -class TagFilter(BaseFilterMixin): - pass +class TagFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin, TagBaseFilterMixin): + color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Webhook, lookups=True) -@autotype_decorator(filtersets.WebhookFilterSet) -class WebhookFilter(BaseFilterMixin): - pass +class WebhookFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + payload_url: FilterLookup[str] | None = strawberry_django.filter_field() + http_method: Annotated['WebhookHttpMethodEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + http_content_type: FilterLookup[str] | None = strawberry_django.filter_field() + additional_headers: FilterLookup[str] | None = strawberry_django.filter_field() + body_template: FilterLookup[str] | None = strawberry_django.filter_field() + secret: FilterLookup[str] | None = strawberry_django.filter_field() + ssl_verification: FilterLookup[bool] | None = strawberry_django.filter_field() + ca_file_path: FilterLookup[str] | None = strawberry_django.filter_field() + events: Annotated['EventRuleFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.EventRule, lookups=True) -@autotype_decorator(filtersets.EventRuleFilterSet) -class EventRuleFilter(BaseFilterMixin): - pass +class EventRuleFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + event_types: Annotated['StringArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + conditions: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + action_type: Annotated['EventRuleActionEnum', strawberry.lazy('extras.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + action_object_type: FilterLookup[str] | None = strawberry_django.filter_field() + action_object_type_id: ID | None = strawberry_django.filter_field() + action_object_id: ID | None = strawberry_django.filter_field() + action_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + comments: FilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/extras/graphql/types.py b/netbox/extras/graphql/types.py index a53c7bed3e7..f4a1a397fc6 100644 --- a/netbox/extras/graphql/types.py +++ b/netbox/extras/graphql/types.py @@ -1,4 +1,4 @@ -from typing import Annotated, List +from typing import Annotated, List, TYPE_CHECKING import strawberry import strawberry_django @@ -8,6 +8,22 @@ from extras.graphql.mixins import CustomFieldsMixin, TagsMixin from netbox.graphql.types import BaseObjectType, ContentTypeType, ObjectType, OrganizationalObjectType from .filters import * +if TYPE_CHECKING: + from core.graphql.types import DataFileType, DataSourceType + from dcim.graphql.types import ( + DeviceRoleType, + DeviceType, + DeviceTypeType, + LocationType, + PlatformType, + RegionType, + SiteGroupType, + SiteType, + ) + from tenancy.graphql.types import TenantGroupType, TenantType + from users.graphql.types import GroupType, UserType + from virtualization.graphql.types import ClusterGroupType, ClusterType, ClusterTypeType, VirtualMachineType + __all__ = ( 'ConfigContextType', 'ConfigTemplateType', @@ -30,12 +46,12 @@ __all__ = ( @strawberry_django.type( models.ConfigContext, fields='__all__', - filters=ConfigContextFilter + filters=ConfigContextFilter, + pagination=True ) class ConfigContextType(ObjectType): data_source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] | None data_file: Annotated["DataFileType", strawberry.lazy('core.graphql.types')] | None - roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]] device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]] tags: List[Annotated["TagType", strawberry.lazy('extras.graphql.types')]] @@ -54,7 +70,8 @@ class ConfigContextType(ObjectType): @strawberry_django.type( models.ConfigTemplate, fields='__all__', - filters=ConfigTemplateFilter + filters=ConfigTemplateFilter, + pagination=True ) class ConfigTemplateType(TagsMixin, ObjectType): data_source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] | None @@ -69,7 +86,8 @@ class ConfigTemplateType(TagsMixin, ObjectType): @strawberry_django.type( models.CustomField, fields='__all__', - filters=CustomFieldFilter + filters=CustomFieldFilter, + pagination=True ) class CustomFieldType(ObjectType): related_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None @@ -78,8 +96,9 @@ class CustomFieldType(ObjectType): @strawberry_django.type( models.CustomFieldChoiceSet, - exclude=('extra_choices', ), - filters=CustomFieldChoiceSetFilter + exclude=['extra_choices'], + filters=CustomFieldChoiceSetFilter, + pagination=True ) class CustomFieldChoiceSetType(ObjectType): @@ -90,7 +109,8 @@ class CustomFieldChoiceSetType(ObjectType): @strawberry_django.type( models.CustomLink, fields='__all__', - filters=CustomLinkFilter + filters=CustomLinkFilter, + pagination=True ) class CustomLinkType(ObjectType): pass @@ -99,7 +119,8 @@ class CustomLinkType(ObjectType): @strawberry_django.type( models.ExportTemplate, fields='__all__', - filters=ExportTemplateFilter + filters=ExportTemplateFilter, + pagination=True ) class ExportTemplateType(ObjectType): data_source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] | None @@ -109,7 +130,8 @@ class ExportTemplateType(ObjectType): @strawberry_django.type( models.ImageAttachment, fields='__all__', - filters=ImageAttachmentFilter + filters=ImageAttachmentFilter, + pagination=True ) class ImageAttachmentType(BaseObjectType): object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None @@ -118,7 +140,8 @@ class ImageAttachmentType(BaseObjectType): @strawberry_django.type( models.JournalEntry, fields='__all__', - filters=JournalEntryFilter + filters=JournalEntryFilter, + pagination=True ) class JournalEntryType(CustomFieldsMixin, TagsMixin, ObjectType): assigned_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None @@ -128,6 +151,7 @@ class JournalEntryType(CustomFieldsMixin, TagsMixin, ObjectType): @strawberry_django.type( models.Notification, # filters=NotificationFilter + pagination=True ) class NotificationType(ObjectType): user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None @@ -135,7 +159,8 @@ class NotificationType(ObjectType): @strawberry_django.type( models.NotificationGroup, - filters=NotificationGroupFilter + filters=NotificationGroupFilter, + pagination=True ) class NotificationGroupType(ObjectType): users: List[Annotated["UserType", strawberry.lazy('users.graphql.types')]] @@ -145,7 +170,8 @@ class NotificationGroupType(ObjectType): @strawberry_django.type( models.SavedFilter, exclude=['content_types',], - filters=SavedFilterFilter + filters=SavedFilterFilter, + pagination=True ) class SavedFilterType(ObjectType): user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None @@ -154,6 +180,7 @@ class SavedFilterType(ObjectType): @strawberry_django.type( models.Subscription, # filters=NotificationFilter + pagination=True ) class SubscriptionType(ObjectType): user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None @@ -162,7 +189,8 @@ class SubscriptionType(ObjectType): @strawberry_django.type( models.Tag, exclude=['extras_taggeditem_items', ], - filters=TagFilter + filters=TagFilter, + pagination=True ) class TagType(ObjectType): color: str @@ -173,7 +201,8 @@ class TagType(ObjectType): @strawberry_django.type( models.Webhook, exclude=['content_types',], - filters=WebhookFilter + filters=WebhookFilter, + pagination=True ) class WebhookType(OrganizationalObjectType): pass @@ -182,7 +211,8 @@ class WebhookType(OrganizationalObjectType): @strawberry_django.type( models.EventRule, exclude=['content_types',], - filters=EventRuleFilter + filters=EventRuleFilter, + pagination=True ) class EventRuleType(OrganizationalObjectType): action_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None diff --git a/netbox/extras/management/commands/housekeeping.py b/netbox/extras/management/commands/housekeeping.py index ade486fc024..ade20a11875 100644 --- a/netbox/extras/management/commands/housekeeping.py +++ b/netbox/extras/management/commands/housekeeping.py @@ -11,6 +11,7 @@ from packaging import version from core.models import Job, ObjectChange from netbox.config import Config +from utilities.proxy import resolve_proxies class Command(BaseCommand): @@ -107,7 +108,7 @@ class Command(BaseCommand): response = requests.get( url=settings.RELEASE_CHECK_URL, headers=headers, - proxies=settings.HTTP_PROXIES + proxies=resolve_proxies(url=settings.RELEASE_CHECK_URL) ) response.raise_for_status() diff --git a/netbox/extras/migrations/0002_squashed_0059.py b/netbox/extras/migrations/0002_squashed_0059.py index b664b286e47..3aa7644fd8f 100644 --- a/netbox/extras/migrations/0002_squashed_0059.py +++ b/netbox/extras/migrations/0002_squashed_0059.py @@ -3,10 +3,10 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('dcim', '0002_auto_20160622_1821'), - ('extras', '0001_initial'), - ('virtualization', '0001_virtualization'), - ('tenancy', '0001_initial'), + ('dcim', '0002_squashed'), + ('extras', '0001_squashed'), + ('virtualization', '0001_squashed_0022'), + ('tenancy', '0001_squashed_0012'), ] replaces = [ diff --git a/netbox/extras/migrations/0060_squashed_0086.py b/netbox/extras/migrations/0060_squashed_0086.py index 3bde7480f2c..2e4437c6b34 100644 --- a/netbox/extras/migrations/0060_squashed_0086.py +++ b/netbox/extras/migrations/0060_squashed_0086.py @@ -45,13 +45,13 @@ class Migration(migrations.Migration): dependencies = [ ('virtualization', '0001_squashed_0022'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('core', '0001_initial'), + ('core', '0001_squashed_0005'), ('contenttypes', '0002_remove_content_type_name'), - ('wireless', '0008_wirelesslan_status'), - ('dcim', '0166_virtualdevicecontext'), - ('tenancy', '0009_standardize_description_comments'), - ('extras', '0059_exporttemplate_as_attachment'), - ('circuits', '0041_standardize_description_comments'), + ('wireless', '0001_squashed_0008'), + ('dcim', '0160_squashed_0166'), + ('tenancy', '0001_squashed_0012'), + ('extras', '0002_squashed_0059'), + ('circuits', '0038_squashed_0042'), ] operations = [ diff --git a/netbox/extras/migrations/0087_squashed_0098.py b/netbox/extras/migrations/0087_squashed_0098.py index 839f4cbe414..21a6116b748 100644 --- a/netbox/extras/migrations/0087_squashed_0098.py +++ b/netbox/extras/migrations/0087_squashed_0098.py @@ -26,9 +26,9 @@ class Migration(migrations.Migration): dependencies = [ ('contenttypes', '0002_remove_content_type_name'), - ('extras', '0086_configtemplate'), + ('extras', '0060_squashed_0086'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('core', '0002_managedfile'), + ('core', '0001_squashed_0005'), ] operations = [ diff --git a/netbox/extras/migrations/0099_cachedvalue_ordering.py b/netbox/extras/migrations/0099_cachedvalue_ordering.py index 36b91d59b5d..d3ddc553357 100644 --- a/netbox/extras/migrations/0099_cachedvalue_ordering.py +++ b/netbox/extras/migrations/0099_cachedvalue_ordering.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('extras', '0098_webhook_custom_field_data_webhook_tags'), + ('extras', '0087_squashed_0098'), ] operations = [ diff --git a/netbox/extras/migrations/0123_remove_staging.py b/netbox/extras/migrations/0123_remove_staging.py new file mode 100644 index 00000000000..643cd912d47 --- /dev/null +++ b/netbox/extras/migrations/0123_remove_staging.py @@ -0,0 +1,27 @@ +# Generated by Django 5.1.5 on 2025-02-20 19:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0122_charfield_null_choices'), + ] + + operations = [ + migrations.RemoveField( + model_name='stagedchange', + name='branch', + ), + migrations.RemoveField( + model_name='stagedchange', + name='object_type', + ), + migrations.DeleteModel( + name='Branch', + ), + migrations.DeleteModel( + name='StagedChange', + ), + ] diff --git a/netbox/extras/migrations/0124_alter_tag_options_tag_weight.py b/netbox/extras/migrations/0124_alter_tag_options_tag_weight.py new file mode 100644 index 00000000000..759ad1595b9 --- /dev/null +++ b/netbox/extras/migrations/0124_alter_tag_options_tag_weight.py @@ -0,0 +1,20 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0123_remove_staging'), + ] + + operations = [ + migrations.AlterModelOptions( + name='tag', + options={'ordering': ('weight', 'name')}, + ), + migrations.AddField( + model_name='tag', + name='weight', + field=models.PositiveSmallIntegerField(default=0), + ), + ] diff --git a/netbox/extras/migrations/0125_exporttemplate_file_name.py b/netbox/extras/migrations/0125_exporttemplate_file_name.py new file mode 100644 index 00000000000..2c8ac118bbe --- /dev/null +++ b/netbox/extras/migrations/0125_exporttemplate_file_name.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0124_alter_tag_options_tag_weight'), + ] + + operations = [ + migrations.AddField( + model_name='exporttemplate', + name='file_name', + field=models.CharField(blank=True, max_length=200), + ), + ] diff --git a/netbox/extras/migrations/0126_configtemplate_as_attachment_and_more.py b/netbox/extras/migrations/0126_configtemplate_as_attachment_and_more.py new file mode 100644 index 00000000000..6d5aad62e78 --- /dev/null +++ b/netbox/extras/migrations/0126_configtemplate_as_attachment_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2b1 on 2025-04-04 20:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0125_exporttemplate_file_name'), + ] + + operations = [ + migrations.AddField( + model_name='configtemplate', + name='as_attachment', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='configtemplate', + name='file_extension', + field=models.CharField(blank=True, max_length=15), + ), + migrations.AddField( + model_name='configtemplate', + name='file_name', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='configtemplate', + name='mime_type', + field=models.CharField(blank=True, max_length=50), + ), + migrations.AddField( + model_name='exporttemplate', + name='environment_params', + field=models.JSONField(blank=True, default=dict, null=True), + ), + ] diff --git a/netbox/extras/models/__init__.py b/netbox/extras/models/__init__.py index e8572103428..f214b1268da 100644 --- a/netbox/extras/models/__init__.py +++ b/netbox/extras/models/__init__.py @@ -5,5 +5,4 @@ from .models import * from .notifications import * from .scripts import * from .search import * -from .staging import * from .tags import * diff --git a/netbox/extras/models/configs.py b/netbox/extras/models/configs.py index 6b52d4c0211..204cc04f976 100644 --- a/netbox/extras/models/configs.py +++ b/netbox/extras/models/configs.py @@ -4,16 +4,13 @@ from django.core.validators import ValidationError from django.db import models from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from jinja2.loaders import BaseLoader -from jinja2.sandbox import SandboxedEnvironment +from extras.models.mixins import RenderTemplateMixin from extras.querysets import ConfigContextQuerySet -from netbox.config import get_config from netbox.models import ChangeLoggedModel from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin from netbox.registry import registry from utilities.data import deepmerge -from utilities.jinja2 import DataFileLoader __all__ = ( 'ConfigContext', @@ -210,7 +207,9 @@ class ConfigContextModel(models.Model): # Config templates # -class ConfigTemplate(SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel): +class ConfigTemplate( + RenderTemplateMixin, SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel +): name = models.CharField( verbose_name=_('name'), max_length=100 @@ -220,20 +219,6 @@ class ConfigTemplate(SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, Ta max_length=200, blank=True ) - template_code = models.TextField( - verbose_name=_('template code'), - help_text=_('Jinja2 template code.') - ) - environment_params = models.JSONField( - verbose_name=_('environment parameters'), - blank=True, - null=True, - default=dict, - help_text=_( - 'Any additional parameters' - ' to pass when constructing the Jinja2 environment.' - ) - ) class Meta: ordering = ('name',) @@ -253,13 +238,8 @@ class ConfigTemplate(SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, Ta self.template_code = self.data_file.data_as_string sync_data.alters_data = True - def render(self, context=None): - """ - Render the contents of the template. - """ + def get_context(self, context=None, queryset=None): _context = dict() - - # Populate the default template context with NetBox model classes, namespaced by app for app, model_names in registry['models'].items(): _context.setdefault(app, {}) for model_name in model_names: @@ -269,37 +249,8 @@ class ConfigTemplate(SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, Ta except LookupError: pass - # Add the provided context data, if any + # Apply the provided context data, if any if context is not None: _context.update(context) - # Initialize the Jinja2 environment and instantiate the Template - environment = self._get_environment() - if self.data_file: - template = environment.get_template(self.data_file.path) - else: - template = environment.from_string(self.template_code) - output = template.render(**_context) - - # Replace CRLF-style line terminators - return output.replace('\r\n', '\n') - - def _get_environment(self): - """ - Instantiate and return a Jinja2 environment suitable for rendering the ConfigTemplate. - """ - # Initialize the template loader & cache the base template code (if applicable) - if self.data_file: - loader = DataFileLoader(data_source=self.data_source) - loader.cache_templates({ - self.data_file.path: self.template_code - }) - else: - loader = BaseLoader() - - # Initialize the environment - env_params = self.environment_params or {} - environment = SandboxedEnvironment(loader=loader, **env_params) - environment.filters.update(get_config().JINJA2_FILTERS) - - return environment + return _context diff --git a/netbox/extras/models/mixins.py b/netbox/extras/models/mixins.py index 0950324c81d..3a7273f93d3 100644 --- a/netbox/extras/models/mixins.py +++ b/netbox/extras/models/mixins.py @@ -1,11 +1,40 @@ +import importlib.abc +import importlib.util import os -from importlib.machinery import SourceFileLoader +import sys +from django.core.files.storage import storages +from django.db import models +from django.utils.translation import gettext_lazy as _ +from django.http import HttpResponse + +from extras.constants import DEFAULT_MIME_TYPE +from extras.utils import filename_from_model, filename_from_object +from utilities.jinja2 import render_jinja2 + __all__ = ( 'PythonModuleMixin', + 'RenderTemplateMixin', ) +class CustomStoragesLoader(importlib.abc.Loader): + """ + Custom loader for exec_module to use django-storages instead of the file system. + """ + def __init__(self, filename): + self.filename = filename + + def create_module(self, spec): + return None # Use default module creation + + def exec_module(self, module): + storage = storages.create_storage(storages.backends["scripts"]) + with storage.open(self.filename, 'rb') as f: + code = f.read() + exec(code, module.__dict__) + + class PythonModuleMixin: def get_jobs(self, name): @@ -33,6 +62,99 @@ class PythonModuleMixin: return name def get_module(self): - loader = SourceFileLoader(self.python_name, self.full_path) - module = loader.load_module() + """ + Load the module using importlib, but use a custom loader to use django-storages + instead of the file system. + """ + spec = importlib.util.spec_from_file_location(self.python_name, self.name) + if spec is None: + raise ModuleNotFoundError(f"Could not find module: {self.python_name}") + loader = CustomStoragesLoader(self.name) + module = importlib.util.module_from_spec(spec) + sys.modules[self.python_name] = module + loader.exec_module(module) + return module + + +class RenderTemplateMixin(models.Model): + """ + Enables support for rendering templates. + """ + template_code = models.TextField( + verbose_name=_('template code'), + help_text=_('Jinja template code.') + ) + environment_params = models.JSONField( + verbose_name=_('environment parameters'), + blank=True, + null=True, + default=dict, + help_text=_( + 'Any additional parameters to pass when constructing the Jinja environment' + ).format(url='https://jinja.palletsprojects.com/en/stable/api/#jinja2.Environment') + ) + mime_type = models.CharField( + max_length=50, + blank=True, + verbose_name=_('MIME type'), + help_text=_('Defaults to {default}').format(default=DEFAULT_MIME_TYPE), + ) + file_name = models.CharField( + max_length=200, + blank=True, + help_text=_('Filename to give to the rendered export file') + ) + file_extension = models.CharField( + verbose_name=_('file extension'), + max_length=15, + blank=True, + help_text=_('Extension to append to the rendered filename') + ) + as_attachment = models.BooleanField( + verbose_name=_('as attachment'), + default=True, + help_text=_("Download file as attachment") + ) + + class Meta: + abstract = True + + def get_context(self, context=None, queryset=None): + raise NotImplementedError(_("{class_name} must implement a get_context() method.").format( + class_name=self.__class__ + )) + + def render(self, context=None, queryset=None): + """ + Render the template with the provided context. The context is passed to the Jinja2 environment as a dictionary. + """ + context = self.get_context(context=context, queryset=queryset) + env_params = self.environment_params or {} + output = render_jinja2(self.template_code, context, env_params) + + # Replace CRLF-style line terminators + output = output.replace('\r\n', '\n') + + return output + + def render_to_response(self, context=None, queryset=None): + output = self.render(context=context, queryset=queryset) + mime_type = self.mime_type or DEFAULT_MIME_TYPE + + # Build the response + response = HttpResponse(output, content_type=mime_type) + + if self.as_attachment: + extension = f'.{self.file_extension}' if self.file_extension else '' + if self.file_name: + filename = self.file_name + elif queryset: + filename = filename_from_model(queryset.model) + elif context: + filename = filename_from_object(context) + else: + filename = "output" + response['Content-Disposition'] = f'attachment; filename="{filename}{extension}"' + + return response diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index d3e443b1441..76fad108218 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -6,7 +6,6 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio from django.contrib.postgres.fields import ArrayField from django.core.validators import ValidationError from django.db import models -from django.http import HttpResponse from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -17,11 +16,12 @@ from extras.choices import * from extras.conditions import ConditionSet from extras.constants import * from extras.utils import image_upload +from extras.models.mixins import RenderTemplateMixin from netbox.config import get_config from netbox.events import get_event_type_choices from netbox.models import ChangeLoggedModel from netbox.models.features import ( - CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, + CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin ) from utilities.html import clean_html from utilities.jinja2 import render_jinja2 @@ -382,7 +382,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): } -class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): +class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderTemplateMixin): object_types = models.ManyToManyField( to='core.ObjectType', related_name='export_templates', @@ -397,32 +397,9 @@ class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, Change max_length=200, blank=True ) - template_code = models.TextField( - help_text=_( - "Jinja2 template code. The list of objects being exported is passed as a context variable named " - "queryset." - ) - ) - mime_type = models.CharField( - max_length=50, - blank=True, - verbose_name=_('MIME type'), - help_text=_('Defaults to text/plain; charset=utf-8') - ) - file_extension = models.CharField( - verbose_name=_('file extension'), - max_length=15, - blank=True, - help_text=_('Extension to append to the rendered filename') - ) - as_attachment = models.BooleanField( - verbose_name=_('as attachment'), - default=True, - help_text=_("Download file as attachment") - ) clone_fields = ( - 'object_types', 'template_code', 'mime_type', 'file_extension', 'as_attachment', + 'object_types', 'template_code', 'mime_type', 'file_name', 'file_extension', 'as_attachment', ) class Meta: @@ -455,37 +432,16 @@ class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, Change self.template_code = self.data_file.data_as_string sync_data.alters_data = True - def render(self, queryset): - """ - Render the contents of the template. - """ - context = { - 'queryset': queryset + def get_context(self, context=None, queryset=None): + _context = { + 'queryset': queryset, } - output = render_jinja2(self.template_code, context) - # Replace CRLF-style line terminators - output = output.replace('\r\n', '\n') + # Apply the provided context data, if any + if context is not None: + _context.update(context) - return output - - def render_to_response(self, queryset): - """ - Render the template to an HTTP response, delivered as a named file attachment - """ - output = self.render(queryset) - mime_type = 'text/plain; charset=utf-8' if not self.mime_type else self.mime_type - - # Build the response - response = HttpResponse(output, content_type=mime_type) - - if self.as_attachment: - basename = queryset.model._meta.verbose_name_plural.replace(' ', '_') - extension = f'.{self.file_extension}' if self.file_extension else '' - filename = f'netbox_{basename}{extension}' - response['Content-Disposition'] = f'attachment; filename="{filename}"' - - return response + return _context class SavedFilter(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): diff --git a/netbox/extras/models/staging.py b/netbox/extras/models/staging.py deleted file mode 100644 index 68d37de7f53..00000000000 --- a/netbox/extras/models/staging.py +++ /dev/null @@ -1,150 +0,0 @@ -import logging -import warnings - -from django.contrib.contenttypes.fields import GenericForeignKey -from django.db import models, transaction -from django.utils.translation import gettext_lazy as _ -from mptt.models import MPTTModel - -from extras.choices import ChangeActionChoices -from netbox.models import ChangeLoggedModel -from netbox.models.features import * -from utilities.serialization import deserialize_object - -__all__ = ( - 'Branch', - 'StagedChange', -) - -logger = logging.getLogger('netbox.staging') - - -class Branch(ChangeLoggedModel): - """ - A collection of related StagedChanges. - """ - name = models.CharField( - verbose_name=_('name'), - max_length=100, - unique=True - ) - description = models.CharField( - verbose_name=_('description'), - max_length=200, - blank=True - ) - user = models.ForeignKey( - to='users.User', - on_delete=models.SET_NULL, - blank=True, - null=True - ) - - class Meta: - ordering = ('name',) - verbose_name = _('branch') - verbose_name_plural = _('branches') - - def __init__(self, *args, **kwargs): - warnings.warn( - 'The staged changes functionality has been deprecated and will be removed in a future release.', - DeprecationWarning - ) - super().__init__(*args, **kwargs) - - def __str__(self): - return f'{self.name} ({self.pk})' - - def merge(self): - logger.info(f'Merging changes in branch {self}') - with transaction.atomic(): - for change in self.staged_changes.all(): - change.apply() - self.staged_changes.all().delete() - - -class StagedChange(CustomValidationMixin, EventRulesMixin, models.Model): - """ - The prepared creation, modification, or deletion of an object to be applied to the active database at a - future point. - """ - branch = models.ForeignKey( - to=Branch, - on_delete=models.CASCADE, - related_name='staged_changes' - ) - action = models.CharField( - verbose_name=_('action'), - max_length=20, - choices=ChangeActionChoices - ) - object_type = models.ForeignKey( - to='contenttypes.ContentType', - on_delete=models.CASCADE, - related_name='+' - ) - object_id = models.PositiveBigIntegerField( - blank=True, - null=True - ) - object = GenericForeignKey( - ct_field='object_type', - fk_field='object_id' - ) - data = models.JSONField( - verbose_name=_('data'), - blank=True, - null=True - ) - - class Meta: - ordering = ('pk',) - indexes = ( - models.Index(fields=('object_type', 'object_id')), - ) - verbose_name = _('staged change') - verbose_name_plural = _('staged changes') - - def __init__(self, *args, **kwargs): - warnings.warn( - 'The staged changes functionality has been deprecated and will be removed in a future release.', - DeprecationWarning - ) - super().__init__(*args, **kwargs) - - def __str__(self): - action = self.get_action_display() - app_label, model_name = self.object_type.natural_key() - return f"{action} {app_label}.{model_name} ({self.object_id})" - - @property - def model(self): - return self.object_type.model_class() - - def apply(self): - """ - Apply the staged create/update/delete action to the database. - """ - if self.action == ChangeActionChoices.ACTION_CREATE: - instance = deserialize_object(self.model, self.data, pk=self.object_id) - logger.info(f'Creating {self.model._meta.verbose_name} {instance}') - instance.save() - - if self.action == ChangeActionChoices.ACTION_UPDATE: - instance = deserialize_object(self.model, self.data, pk=self.object_id) - logger.info(f'Updating {self.model._meta.verbose_name} {instance}') - instance.save() - - if self.action == ChangeActionChoices.ACTION_DELETE: - instance = self.model.objects.get(pk=self.object_id) - logger.info(f'Deleting {self.model._meta.verbose_name} {instance}') - instance.delete() - - # Rebuild the MPTT tree where applicable - if issubclass(self.model, MPTTModel): - self.model.objects.rebuild() - - apply.alters_data = True - - def get_action_color(self): - return ChangeActionChoices.colors.get(self.action) diff --git a/netbox/extras/models/tags.py b/netbox/extras/models/tags.py index d1e329f03f7..4c6396172da 100644 --- a/netbox/extras/models/tags.py +++ b/netbox/extras/models/tags.py @@ -9,6 +9,7 @@ from netbox.choices import ColorChoices from netbox.models import ChangeLoggedModel from netbox.models.features import CloningMixin, ExportTemplatesMixin from utilities.fields import ColorField +from utilities.querysets import RestrictedQuerySet __all__ = ( 'Tag', @@ -39,13 +40,17 @@ class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase): blank=True, help_text=_("The object type(s) to which this tag can be applied.") ) + weight = models.PositiveSmallIntegerField( + verbose_name=_('weight'), + default=0, + ) clone_fields = ( 'color', 'description', 'object_types', ) class Meta: - ordering = ['name'] + ordering = ('weight', 'name') verbose_name = _('tag') verbose_name_plural = _('tags') @@ -72,6 +77,7 @@ class TaggedItem(GenericTaggedItemBase): ) _netbox_private = True + objects = RestrictedQuerySet.as_manager() class Meta: indexes = [models.Index(fields=["content_type", "object_id"])] diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index f2bd75a1dc0..83195402d21 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -2,10 +2,12 @@ import inspect import json import logging import os +import re import yaml from django import forms from django.conf import settings +from django.core.files.storage import storages from django.core.validators import RegexValidator from django.utils import timezone from django.utils.functional import classproperty @@ -367,9 +369,46 @@ class BaseScript: def filename(self): return inspect.getfile(self.__class__) + def findsource(self, object): + storage = storages.create_storage(storages.backends["scripts"]) + with storage.open(os.path.basename(self.filename), 'r') as f: + data = f.read() + + # Break the source code into lines + lines = [line + '\n' for line in data.splitlines()] + + # Find the class definition + name = object.__name__ + pat = re.compile(r'^(\s*)class\s*' + name + r'\b') + # use the class definition with the least indentation + candidates = [] + for i in range(len(lines)): + match = pat.match(lines[i]) + if match: + if lines[i][0] == 'c': + return lines, i + + candidates.append((match.group(1), i)) + if not candidates: + raise OSError('could not find class definition') + + # Sort the candidates by whitespace, and by line number + candidates.sort() + return lines, candidates[0][1] + @property def source(self): - return inspect.getsource(self.__class__) + # Can't use inspect.getsource() as it uses os to get the file + # inspect uses ast, but that is overkill for this as we only do + # classes. + object = self.__class__ + + try: + lines, lnum = self.findsource(object) + lines = inspect.getblock(lines[lnum:]) + return ''.join(lines) + except OSError: + return '' @classmethod def _get_vars(cls): @@ -524,7 +563,12 @@ class BaseScript: def load_yaml(self, filename): """ Return data from a YAML file + TODO: DEPRECATED: Remove this method in v4.4 """ + self._log( + _("load_yaml is deprecated and will be removed in v4.4"), + level=LogLevelChoices.LOG_WARNING + ) try: from yaml import CLoader as Loader except ImportError: @@ -539,7 +583,12 @@ class BaseScript: def load_json(self, filename): """ Return data from a JSON file + TODO: DEPRECATED: Remove this method in v4.4 """ + self._log( + _("load_json is deprecated and will be removed in v4.4"), + level=LogLevelChoices.LOG_WARNING + ) file_path = os.path.join(settings.SCRIPTS_ROOT, filename) with open(file_path, 'r') as datafile: data = json.load(datafile) @@ -555,7 +604,6 @@ class BaseScript: Run the report and save its results. Each test method will be executed in order. """ self.logger.info("Running report") - try: for test_name in self.tests: self._current_test = test_name diff --git a/netbox/extras/storage.py b/netbox/extras/storage.py new file mode 100644 index 00000000000..ede4fac7f1b --- /dev/null +++ b/netbox/extras/storage.py @@ -0,0 +1,14 @@ +from django.conf import settings +from django.core.files.storage import FileSystemStorage +from django.utils.functional import cached_property + + +class ScriptFileSystemStorage(FileSystemStorage): + """ + Custom storage for scripts - for django-storages as the default one will + go off media-root and raise security errors as the scripts can be outside + the media-root directory. + """ + @cached_property + def base_location(self): + return settings.SCRIPTS_ROOT diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index e538c488ec0..60b2070581a 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -183,6 +183,15 @@ class ExportTemplateTable(NetBoxTable): object_types = columns.ContentTypesColumn( verbose_name=_('Object Types'), ) + mime_type = tables.Column( + verbose_name=_('MIME Type') + ) + file_name = tables.Column( + verbose_name=_('File Name'), + ) + file_extension = tables.Column( + verbose_name=_('File Extension'), + ) as_attachment = columns.BooleanColumn( verbose_name=_('As Attachment'), false_mark=None @@ -203,11 +212,12 @@ class ExportTemplateTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ExportTemplate fields = ( - 'pk', 'id', 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment', - 'data_source', 'data_file', 'data_synced', 'created', 'last_updated', + 'pk', 'id', 'name', 'object_types', 'description', 'mime_type', 'file_name', 'file_extension', + 'as_attachment', 'data_source', 'data_file', 'data_synced', 'created', 'last_updated', ) default_columns = ( - 'pk', 'name', 'object_types', 'description', 'mime_type', 'file_extension', 'as_attachment', 'is_synced', + 'pk', 'name', 'object_types', 'description', 'mime_type', 'file_name', 'file_extension', + 'as_attachment', 'is_synced', ) @@ -449,8 +459,8 @@ class TagTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Tag fields = ( - 'pk', 'id', 'name', 'items', 'slug', 'color', 'description', 'object_types', 'created', 'last_updated', - 'actions', + 'pk', 'id', 'name', 'items', 'slug', 'color', 'weight', 'description', 'object_types', + 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'name', 'items', 'slug', 'color', 'description') @@ -526,6 +536,19 @@ class ConfigTemplateTable(NetBoxTable): orderable=False, verbose_name=_('Synced') ) + mime_type = tables.Column( + verbose_name=_('MIME Type') + ) + file_name = tables.Column( + verbose_name=_('File Name'), + ) + file_extension = tables.Column( + verbose_name=_('File Extension'), + ) + as_attachment = columns.BooleanColumn( + verbose_name=_('As Attachment'), + false_mark=None + ) tags = columns.TagColumn( url_name='extras:configtemplate_list' ) @@ -553,8 +576,9 @@ class ConfigTemplateTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ConfigTemplate fields = ( - 'pk', 'id', 'name', 'description', 'data_source', 'data_file', 'data_synced', 'role_count', - 'platform_count', 'device_count', 'vm_count', 'created', 'last_updated', 'tags', + 'pk', 'id', 'name', 'description', 'data_source', 'data_file', 'data_synced', 'as_attachment', + 'mime_type', 'file_name', 'file_extension', 'role_count', 'platform_count', 'device_count', + 'vm_count', 'created', 'last_updated', 'tags', ) default_columns = ( 'pk', 'name', 'description', 'is_synced', 'device_count', 'vm_count', diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index 63baf44d30e..6e3fb37fc04 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -479,6 +479,7 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase): 'object_types': ['dcim.device'], 'name': 'Test Export Template 6', 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', + 'file_name': 'test_export_template_6', }, ] bulk_update_data = { @@ -494,7 +495,9 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase): ), ExportTemplate( name='Export Template 2', - template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}' + template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}', + file_name='export_template_2', + file_extension='test', ), ExportTemplate( name='Export Template 3', @@ -502,8 +505,10 @@ class ExportTemplateTest(APIViewTestCases.APIViewTestCase): ), ) ExportTemplate.objects.bulk_create(export_templates) + + device_object_type = ObjectType.objects.get_for_model(Device) for et in export_templates: - et.object_types.set([ObjectType.objects.get_for_model(Device)]) + et.object_types.set([device_object_type]) class TagTest(APIViewTestCases.APIViewTestCase): @@ -513,6 +518,7 @@ class TagTest(APIViewTestCases.APIViewTestCase): { 'name': 'Tag 4', 'slug': 'tag-4', + 'weight': 1000, }, { 'name': 'Tag 5', @@ -527,6 +533,24 @@ class TagTest(APIViewTestCases.APIViewTestCase): 'description': 'New description', } + @classmethod + def setUpTestData(cls): + + tags = ( + Tag(name='Tag 1', slug='tag-1'), + Tag(name='Tag 2', slug='tag-2'), + Tag(name='Tag 3', slug='tag-3', weight=26), + ) + Tag.objects.bulk_create(tags) + + +class TaggedItemTest( + APIViewTestCases.GetObjectViewTestCase, + APIViewTestCases.ListObjectsViewTestCase +): + model = TaggedItem + brief_fields = ['display', 'id', 'object', 'object_id', 'object_type', 'tag', 'url'] + @classmethod def setUpTestData(cls): @@ -537,6 +561,16 @@ class TagTest(APIViewTestCases.APIViewTestCase): ) Tag.objects.bulk_create(tags) + sites = ( + Site(name='Site 1', slug='site-1'), + Site(name='Site 2', slug='site-2'), + Site(name='Site 3', slug='site-3'), + ) + Site.objects.bulk_create(sites) + sites[0].tags.set([tags[0], tags[1]]) + sites[1].tags.set([tags[1], tags[2]]) + sites[2].tags.set([tags[2], tags[0]]) + # TODO: Standardize to APIViewTestCase (needs create & update tests) class ImageAttachmentTest( @@ -721,6 +755,10 @@ class ConfigTemplateTest(APIViewTestCases.APIViewTestCase): { 'name': 'Config Template 4', 'template_code': 'Foo: {{ foo }}', + 'mime_type': 'text/plain', + 'file_name': 'output4', + 'file_extension': 'txt', + 'as_attachment': True, }, { 'name': 'Config Template 5', @@ -744,7 +782,7 @@ class ConfigTemplateTest(APIViewTestCases.APIViewTestCase): ), ConfigTemplate( name='Config Template 2', - template_code='Bar: {{ bar }}' + template_code='Bar: {{ bar }}', ), ConfigTemplate( name='Config Template 3', diff --git a/netbox/extras/tests/test_filtersets.py b/netbox/extras/tests/test_filtersets.py index cf914e665c5..987dfe0ff26 100644 --- a/netbox/extras/tests/test_filtersets.py +++ b/netbox/extras/tests/test_filtersets.py @@ -616,16 +616,39 @@ class BookmarkTestCase(TestCase, BaseFilterSetTests): class ExportTemplateTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = ExportTemplate.objects.all() filterset = ExportTemplateFilterSet - ignore_fields = ('template_code', 'data_path') + ignore_fields = ('template_code', 'environment_params', 'data_path') @classmethod def setUpTestData(cls): object_types = ObjectType.objects.filter(model__in=['site', 'rack', 'device']) export_templates = ( - ExportTemplate(name='Export Template 1', template_code='TESTING', description='foobar1'), - ExportTemplate(name='Export Template 2', template_code='TESTING', description='foobar2'), - ExportTemplate(name='Export Template 3', template_code='TESTING'), + ExportTemplate( + name='Export Template 1', + template_code='TESTING', + description='foobar1', + mime_type='text/foo', + file_name='foo', + file_extension='foo', + as_attachment=True, + ), + ExportTemplate( + name='Export Template 2', + template_code='TESTING', + description='foobar2', + mime_type='text/bar', + file_name='bar', + file_extension='bar', + as_attachment=True, + ), + ExportTemplate( + name='Export Template 3', + template_code='TESTING', + mime_type='text/baz', + file_name='baz', + file_extension='baz', + as_attachment=False, + ), ) ExportTemplate.objects.bulk_create(export_templates) for i, et in enumerate(export_templates): @@ -649,6 +672,22 @@ class ExportTemplateTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'description': ['foobar1', 'foobar2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_mime_type(self): + params = {'mime_type': ['text/foo', 'text/bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_file_name(self): + params = {'file_name': ['foo', 'bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_file_extension(self): + params = {'file_extension': ['foo', 'bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_as_attachment(self): + params = {'as_attachment': True} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = ImageAttachment.objects.all() @@ -884,7 +923,8 @@ class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests): DeviceRole(name='Device Role 2', slug='device-role-2'), DeviceRole(name='Device Role 3', slug='device-role-3'), ) - DeviceRole.objects.bulk_create(device_roles) + for device_role in device_roles: + device_role.save() platforms = ( Platform(name='Platform 1', slug='platform-1'), @@ -1067,9 +1107,32 @@ class ConfigTemplateTestCase(TestCase, ChangeLoggedFilterSetTests): @classmethod def setUpTestData(cls): config_templates = ( - ConfigTemplate(name='Config Template 1', template_code='TESTING', description='foobar1'), - ConfigTemplate(name='Config Template 2', template_code='TESTING', description='foobar2'), - ConfigTemplate(name='Config Template 3', template_code='TESTING'), + ConfigTemplate( + name='Config Template 1', + template_code='TESTING', + description='foobar1', + mime_type='text/foo', + file_name='foo', + file_extension='foo', + as_attachment=True, + ), + ConfigTemplate( + name='Config Template 2', + template_code='TESTING', + description='foobar2', + mime_type='text/bar', + file_name='bar', + file_extension='bar', + as_attachment=True, + ), + ConfigTemplate( + name='Config Template 3', + template_code='TESTING', + mime_type='text/baz', + file_name='baz', + file_extension='baz', + as_attachment=False, + ), ) ConfigTemplate.objects.bulk_create(config_templates) @@ -1085,6 +1148,22 @@ class ConfigTemplateTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'description': ['foobar1', 'foobar2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_mime_type(self): + params = {'mime_type': ['text/foo', 'text/bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_file_name(self): + params = {'file_name': ['foo', 'bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_file_extension(self): + params = {'file_extension': ['foo', 'bar']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_as_attachment(self): + params = {'as_attachment': True} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + class TagTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = Tag.objects.all() @@ -1140,6 +1219,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): 'module', 'modulebay', 'moduletype', + 'moduletypeprofile', 'platform', 'powerfeed', 'poweroutlet', @@ -1196,7 +1276,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): tags = ( Tag(name='Tag 1', slug='tag-1', color='ff0000', description='foobar1'), Tag(name='Tag 2', slug='tag-2', color='00ff00', description='foobar2'), - Tag(name='Tag 3', slug='tag-3', color='0000ff'), + Tag(name='Tag 3', slug='tag-3', color='0000ff', weight=1000), ) Tag.objects.bulk_create(tags) tags[0].object_types.add(object_types['site']) @@ -1249,6 +1329,69 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): ['Tag 2', 'Tag 3'] ) + def test_weight(self): + params = {'weight': [1000]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + params = {'weight': [0]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) + + +class TaggedItemFilterSetTestCase(TestCase): + queryset = TaggedItem.objects.all() + filterset = TaggedItemFilterSet + + @classmethod + def setUpTestData(cls): + tags = ( + Tag(name='Tag 1', slug='tag-1'), + Tag(name='Tag 2', slug='tag-2'), + Tag(name='Tag 3', slug='tag-3'), + ) + Tag.objects.bulk_create(tags) + + sites = ( + Site(name='Site 1', slug='site-1'), + Site(name='Site 2', slug='site-2'), + Site(name='Site 3', slug='site-3'), + ) + Site.objects.bulk_create(sites) + sites[0].tags.add(tags[0]) + sites[1].tags.add(tags[1]) + sites[2].tags.add(tags[2]) + + tenants = ( + Tenant(name='Tenant 1', slug='tenant-1'), + Tenant(name='Tenant 2', slug='tenant-2'), + Tenant(name='Tenant 3', slug='tenant-3'), + ) + Tenant.objects.bulk_create(tenants) + tenants[0].tags.add(tags[0]) + tenants[1].tags.add(tags[1]) + tenants[2].tags.add(tags[2]) + + def test_tag(self): + tags = Tag.objects.all()[:2] + params = {'tag': [tags[0].slug, tags[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'tag_id': [tags[0].pk, tags[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_object_type(self): + object_type = ObjectType.objects.get_for_model(Site) + params = {'object_type': 'dcim.site'} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) + params = {'object_type_id': [object_type.pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) + + def test_object_id(self): + site_ids = Site.objects.values_list('pk', flat=True) + params = { + 'object_type': 'dcim.site', + 'object_id': site_ids[:2], + } + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + class ChangeLoggedFilterSetTestCase(TestCase): """ diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index c90390dd179..bf05a8c1878 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -10,6 +10,40 @@ from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMac class TagTest(TestCase): + def test_default_ordering_weight_then_name_is_set(self): + Tag.objects.create(name='Tag 1', slug='tag-1', weight=100) + Tag.objects.create(name='Tag 2', slug='tag-2') + Tag.objects.create(name='Tag 3', slug='tag-3', weight=10) + Tag.objects.create(name='Tag 4', slug='tag-4', weight=10) + + tags = Tag.objects.all() + + self.assertEqual(tags[0].slug, 'tag-2') + self.assertEqual(tags[1].slug, 'tag-3') + self.assertEqual(tags[2].slug, 'tag-4') + self.assertEqual(tags[3].slug, 'tag-1') + + def test_tag_related_manager_ordering_weight_then_name(self): + tags = [ + Tag.objects.create(name='Tag 1', slug='tag-1', weight=100), + Tag.objects.create(name='Tag 2', slug='tag-2'), + Tag.objects.create(name='Tag 3', slug='tag-3', weight=10), + Tag.objects.create(name='Tag 4', slug='tag-4', weight=10), + ] + + site = Site.objects.create(name='Site 1') + for tag in tags: + site.tags.add(tag) + site.save() + + site = Site.objects.first() + tags = site.tags.all() + + self.assertEqual(tags[0].slug, 'tag-2') + self.assertEqual(tags[1].slug, 'tag-3') + self.assertEqual(tags[2].slug, 'tag-4') + self.assertEqual(tags[3].slug, 'tag-1') + def test_create_tag_unicode(self): tag = Tag(name='Testing Unicode: 台灣') tag.save() diff --git a/netbox/extras/tests/test_utils.py b/netbox/extras/tests/test_utils.py new file mode 100644 index 00000000000..b851acab83f --- /dev/null +++ b/netbox/extras/tests/test_utils.py @@ -0,0 +1,19 @@ +from django.test import TestCase + +from extras.models import ExportTemplate +from extras.utils import filename_from_model +from tenancy.models import ContactGroup, TenantGroup +from wireless.models import WirelessLANGroup + + +class FilenameFromModelTests(TestCase): + def test_expected_output(self): + cases = ( + (ExportTemplate, 'netbox_export_templates'), + (ContactGroup, 'netbox_contact_groups'), + (TenantGroup, 'netbox_tenant_groups'), + (WirelessLANGroup, 'netbox_wireless_lan_groups'), + ) + + for model, expected in cases: + self.assertEqual(filename_from_model(model), expected) diff --git a/netbox/extras/tests/test_views.py b/netbox/extras/tests/test_views.py index 5d82fae4ca8..6378b29b8f3 100644 --- a/netbox/extras/tests/test_views.py +++ b/netbox/extras/tests/test_views.py @@ -301,11 +301,14 @@ class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase): def setUpTestData(cls): site_type = ObjectType.objects.get_for_model(Site) TEMPLATE_CODE = """{% for object in queryset %}{{ object }}{% endfor %}""" + ENVIRONMENT_PARAMS = """{"trim_blocks": true}""" export_templates = ( ExportTemplate(name='Export Template 1', template_code=TEMPLATE_CODE), - ExportTemplate(name='Export Template 2', template_code=TEMPLATE_CODE), - ExportTemplate(name='Export Template 3', template_code=TEMPLATE_CODE), + ExportTemplate( + name='Export Template 2', template_code=TEMPLATE_CODE, environment_params={"trim_blocks": True} + ), + ExportTemplate(name='Export Template 3', template_code=TEMPLATE_CODE, file_name='export_template_3') ) ExportTemplate.objects.bulk_create(export_templates) for et in export_templates: @@ -315,13 +318,15 @@ class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase): 'name': 'Export Template X', 'object_types': [site_type.pk], 'template_code': TEMPLATE_CODE, + 'environment_params': ENVIRONMENT_PARAMS, + 'file_name': 'template_x', } cls.csv_data = ( - "name,object_types,template_code", - f"Export Template 4,dcim.site,{TEMPLATE_CODE}", - f"Export Template 5,dcim.site,{TEMPLATE_CODE}", - f"Export Template 6,dcim.site,{TEMPLATE_CODE}", + "name,object_types,template_code,file_name", + f"Export Template 4,dcim.site,{TEMPLATE_CODE},", + f"Export Template 5,dcim.site,{TEMPLATE_CODE},template_5", + f"Export Template 6,dcim.site,{TEMPLATE_CODE},", ) cls.csv_update_data = ( @@ -441,8 +446,8 @@ class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase): tags = ( Tag(name='Tag 1', slug='tag-1'), - Tag(name='Tag 2', slug='tag-2'), - Tag(name='Tag 3', slug='tag-3'), + Tag(name='Tag 2', slug='tag-2', weight=1), + Tag(name='Tag 3', slug='tag-3', weight=32767), ) Tag.objects.bulk_create(tags) @@ -451,13 +456,14 @@ class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase): 'slug': 'tag-x', 'color': 'c0c0c0', 'comments': 'Some comments', + 'weight': 11, } cls.csv_data = ( - "name,slug,color,description", - "Tag 4,tag-4,ff0000,Fourth tag", - "Tag 5,tag-5,00ff00,Fifth tag", - "Tag 6,tag-6,0000ff,Sixth tag", + "name,slug,color,description,weight", + "Tag 4,tag-4,ff0000,Fourth tag,0", + "Tag 5,tag-5,00ff00,Fifth tag,1111", + "Tag 6,tag-6,0000ff,Sixth tag,0", ) cls.csv_update_data = ( @@ -535,11 +541,23 @@ class ConfigTemplateTestCase( @classmethod def setUpTestData(cls): TEMPLATE_CODE = """Foo: {{ foo }}""" + ENVIRONMENT_PARAMS = """{"trim_blocks": true}""" config_templates = ( - ConfigTemplate(name='Config Template 1', template_code=TEMPLATE_CODE), - ConfigTemplate(name='Config Template 2', template_code=TEMPLATE_CODE), - ConfigTemplate(name='Config Template 3', template_code=TEMPLATE_CODE), + ConfigTemplate( + name='Config Template 1', + template_code=TEMPLATE_CODE) + , + ConfigTemplate( + name='Config Template 2', + template_code=TEMPLATE_CODE, + environment_params={"trim_blocks": True}, + ), + ConfigTemplate( + name='Config Template 3', + template_code=TEMPLATE_CODE, + file_name='config_template_3', + ), ) ConfigTemplate.objects.bulk_create(config_templates) @@ -547,6 +565,8 @@ class ConfigTemplateTestCase( 'name': 'Config Template X', 'description': 'Config template', 'template_code': TEMPLATE_CODE, + 'environment_params': ENVIRONMENT_PARAMS, + 'file_name': 'config_x', } cls.csv_update_data = ( @@ -558,6 +578,10 @@ class ConfigTemplateTestCase( cls.bulk_edit_data = { 'description': 'New description', + 'mime_type': 'text/html', + 'file_name': 'output', + 'file_extension': 'html', + 'as_attachment': True, } diff --git a/netbox/extras/utils.py b/netbox/extras/utils.py index efe7ada5bbc..155597c3012 100644 --- a/netbox/extras/utils.py +++ b/netbox/extras/utils.py @@ -1,6 +1,7 @@ import importlib from django.core.exceptions import ImproperlyConfigured +from django.db import models from taggit.managers import _TaggableManager from netbox.context import current_request @@ -15,6 +16,23 @@ __all__ = ( ) +def filename_from_model(model: models.Model) -> str: + """Standardises how we generate filenames from model class for exports""" + base = model._meta.verbose_name_plural.lower().replace(' ', '_') + return f'netbox_{base}' + + +def filename_from_object(context: dict) -> str: + """Standardises how we generate filenames from model class for exports""" + if 'device' in context: + base = f"{context['device'].name or 'config'}" + elif 'virtualmachine' in context: + base = f"{context['virtualmachine'].name or 'config'}" + else: + base = 'config' + return base + + def is_taggable(obj): """ Return True if the instance can have Tags assigned to it; False otherwise. diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 9cb9dd54ac9..2833cec0de0 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -12,7 +12,6 @@ from django.utils.translation import gettext as _ from django.views.generic import View from core.choices import ManagedFileRootPathChoices -from core.forms import ManagedFileForm from core.models import Job from core.tables import JobTable from dcim.models import Device, DeviceRole, Platform @@ -1163,7 +1162,7 @@ class DashboardWidgetDeleteView(LoginRequiredMixin, View): @register_model_view(ScriptModule, 'edit') class ScriptModuleCreateView(generic.ObjectEditView): queryset = ScriptModule.objects.all() - form = ManagedFileForm + form = forms.ScriptFileForm def alter_object(self, obj, *args, **kwargs): obj.file_root = ManagedFileRootPathChoices.SCRIPTS diff --git a/netbox/extras/webhooks.py b/netbox/extras/webhooks.py index 889c97ac27b..368075217dd 100644 --- a/netbox/extras/webhooks.py +++ b/netbox/extras/webhooks.py @@ -3,10 +3,10 @@ import hmac import logging import requests -from django.conf import settings from django_rq import job from jinja2.exceptions import TemplateError +from utilities.proxy import resolve_proxies from .constants import WEBHOOK_EVENT_TYPES logger = logging.getLogger('netbox.webhooks') @@ -63,9 +63,10 @@ def send_webhook(event_rule, model_name, event_type, data, timestamp, username, raise e # Prepare the HTTP request + url = webhook.render_payload_url(context) params = { 'method': webhook.http_method, - 'url': webhook.render_payload_url(context), + 'url': url, 'headers': headers, 'data': body.encode('utf8'), } @@ -88,7 +89,8 @@ def send_webhook(event_rule, model_name, event_type, data, timestamp, username, session.verify = webhook.ssl_verification if webhook.ca_file_path: session.verify = webhook.ca_file_path - response = session.send(prepared_request, proxies=settings.HTTP_PROXIES) + proxies = resolve_proxies(url=url, context={'client': webhook}) + response = session.send(prepared_request, proxies=proxies) if 200 <= response.status_code <= 299: logger.info(f"Request succeeded; response status {response.status_code}") diff --git a/netbox/ipam/api/serializers_/ip.py b/netbox/ipam/api/serializers_/ip.py index bfc7ac5465c..6f815b5cec4 100644 --- a/netbox/ipam/api/serializers_/ip.py +++ b/netbox/ipam/api/serializers_/ip.py @@ -147,7 +147,8 @@ class IPRangeSerializer(NetBoxModelSerializer): fields = [ 'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant', 'status', 'role', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', - 'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', + 'mark_populated', 'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', + 'last_updated', ] brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description') diff --git a/netbox/ipam/api/serializers_/vlans.py b/netbox/ipam/api/serializers_/vlans.py index 9b5501dc5f0..a6f42834342 100644 --- a/netbox/ipam/api/serializers_/vlans.py +++ b/netbox/ipam/api/serializers_/vlans.py @@ -37,6 +37,7 @@ class VLANGroupSerializer(NetBoxModelSerializer): scope = serializers.SerializerMethodField(read_only=True) vid_ranges = IntegerRangeSerializer(many=True, required=False) utilization = serializers.CharField(read_only=True) + tenant = TenantSerializer(nested=True, required=False, allow_null=True) # Related object counts vlan_count = RelatedObjectCountField('vlans') @@ -45,7 +46,7 @@ class VLANGroupSerializer(NetBoxModelSerializer): model = VLANGroup fields = [ 'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'vid_ranges', - 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization' + 'tenant', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization' ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count') validators = [] diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index 12a36fbe1eb..ba8b45e1476 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -478,7 +478,7 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet): class Meta: model = IPRange - fields = ('id', 'mark_utilized', 'size', 'description') + fields = ('id', 'mark_populated', 'mark_utilized', 'size', 'description') def search(self, queryset, name, value): if not value.strip(): @@ -867,7 +867,7 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet): ) -class VLANGroupFilterSet(OrganizationalModelFilterSet): +class VLANGroupFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): scope_type = ContentTypeFilter() region = django_filters.NumberFilter( method='filter_scope' diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py index 2a071da8c68..411208eeb88 100644 --- a/netbox/ipam/forms/bulk_edit.py +++ b/netbox/ipam/forms/bulk_edit.py @@ -296,6 +296,11 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): queryset=Role.objects.all(), required=False ) + mark_populated = forms.NullBooleanField( + required=False, + widget=BulkEditNullBooleanSelect(), + label=_('Treat as populated') + ) mark_utilized = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), @@ -435,11 +440,17 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): label=_('VLAN ID ranges'), required=False ) + tenant = DynamicModelChoiceField( + label=_('Tenant'), + queryset=Tenant.objects.all(), + required=False + ) model = VLANGroup fieldsets = ( FieldSet('site', 'vid_ranges', 'description'), FieldSet('scope_type', 'scope', name=_('Scope')), + FieldSet('tenant', name=_('Tenancy')), ) nullable_fields = ('description', 'scope') diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index 65a6e5601d3..8cc034696e6 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -268,8 +268,8 @@ class IPRangeImportForm(NetBoxModelImportForm): class Meta: model = IPRange fields = ( - 'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'mark_utilized', 'description', - 'comments', 'tags', + 'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'mark_populated', 'mark_utilized', + 'description', 'comments', 'tags', ) @@ -445,10 +445,17 @@ class VLANGroupImportForm(NetBoxModelImportForm): vid_ranges = NumericRangeArrayField( required=False ) + tenant = CSVModelChoiceField( + label=_('Tenant'), + queryset=Tenant.objects.all(), + required=False, + to_field_name='name', + help_text=_('Assigned tenant') + ) class Meta: model = VLANGroup - fields = ('name', 'slug', 'scope_type', 'scope_id', 'vid_ranges', 'description', 'tags') + fields = ('name', 'slug', 'scope_type', 'scope_id', 'vid_ranges', 'tenant', 'description', 'tags') labels = { 'scope_id': 'Scope ID', } diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py index e6aef30545f..f8184a0fb25 100644 --- a/netbox/ipam/forms/filtersets.py +++ b/netbox/ipam/forms/filtersets.py @@ -266,7 +266,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = IPRange fieldsets = ( FieldSet('q', 'filter_id', 'tag'), - FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_utilized', name=_('Attributes')), + FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), ) family = forms.ChoiceField( @@ -291,6 +291,13 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): null_option='None', label=_('Role') ) + mark_populated = forms.NullBooleanField( + required=False, + label=_('Treat as populated'), + widget=forms.Select( + choices=BOOLEAN_WITH_BLANK_CHOICES + ) + ) mark_utilized = forms.NullBooleanField( required=False, label=_('Treat as fully utilized'), @@ -416,12 +423,13 @@ class FHRPGroupFilterForm(NetBoxModelFilterSetForm): tag = TagFilterField(model) -class VLANGroupFilterForm(NetBoxModelFilterSetForm): +class VLANGroupFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): fieldsets = ( FieldSet('q', 'filter_id', 'tag'), FieldSet('region', 'sitegroup', 'site', 'location', 'rack', name=_('Location')), FieldSet('cluster_group', 'cluster', name=_('Cluster')), FieldSet('contains_vid', name=_('VLANs')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), ) model = VLANGroup region = DynamicModelMultipleChoiceField( diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index d7c6b17df86..5ce3e9851ed 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -257,8 +257,8 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): fieldsets = ( FieldSet( - 'vrf', 'start_address', 'end_address', 'role', 'status', 'mark_utilized', 'description', 'tags', - name=_('IP Range') + 'vrf', 'start_address', 'end_address', 'role', 'status', 'mark_populated', 'mark_utilized', 'description', + 'tags', name=_('IP Range') ), FieldSet('tenant_group', 'tenant', name=_('Tenancy')), ) @@ -266,8 +266,8 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): class Meta: model = IPRange fields = [ - 'vrf', 'start_address', 'end_address', 'status', 'role', 'tenant_group', 'tenant', 'mark_utilized', - 'description', 'comments', 'tags', + 'vrf', 'start_address', 'end_address', 'status', 'role', 'tenant_group', 'tenant', 'mark_populated', + 'mark_utilized', 'description', 'comments', 'tags', ] @@ -616,7 +616,7 @@ class FHRPGroupAssignmentForm(forms.ModelForm): return group -class VLANGroupForm(NetBoxModelForm): +class VLANGroupForm(TenancyForm, NetBoxModelForm): slug = SlugField() vid_ranges = NumericRangeArrayField( label=_('VLAN IDs') @@ -639,12 +639,13 @@ class VLANGroupForm(NetBoxModelForm): FieldSet('name', 'slug', 'description', 'tags', name=_('VLAN Group')), FieldSet('vid_ranges', name=_('Child VLANs')), FieldSet('scope_type', 'scope', name=_('Scope')), + FieldSet('tenant_group', 'tenant', name=_('Tenancy')), ) class Meta: model = VLANGroup fields = [ - 'name', 'slug', 'description', 'vid_ranges', 'scope_type', 'tags', + 'name', 'slug', 'description', 'vid_ranges', 'scope_type', 'tenant_group', 'tenant', 'tags', ] def __init__(self, *args, **kwargs): diff --git a/netbox/ipam/graphql/enums.py b/netbox/ipam/graphql/enums.py new file mode 100644 index 00000000000..34fb1a6fdbb --- /dev/null +++ b/netbox/ipam/graphql/enums.py @@ -0,0 +1,27 @@ +import strawberry + +from ipam.choices import * + +__all__ = ( + 'FHRPGroupAuthTypeEnum', + 'FHRPGroupProtocolEnum', + 'IPAddressFamilyEnum', + 'IPAddressRoleEnum', + 'IPAddressStatusEnum', + 'IPRangeStatusEnum', + 'PrefixStatusEnum', + 'ServiceProtocolEnum', + 'VLANStatusEnum', + 'VLANQinQRoleEnum', +) + +FHRPGroupAuthTypeEnum = strawberry.enum(FHRPGroupAuthTypeChoices.as_enum()) +FHRPGroupProtocolEnum = strawberry.enum(FHRPGroupProtocolChoices.as_enum()) +IPAddressFamilyEnum = strawberry.enum(IPAddressFamilyChoices.as_enum()) +IPAddressRoleEnum = strawberry.enum(IPAddressRoleChoices.as_enum()) +IPAddressStatusEnum = strawberry.enum(IPAddressStatusChoices.as_enum()) +IPRangeStatusEnum = strawberry.enum(IPRangeStatusChoices.as_enum()) +PrefixStatusEnum = strawberry.enum(PrefixStatusChoices.as_enum()) +ServiceProtocolEnum = strawberry.enum(ServiceProtocolChoices.as_enum()) +VLANStatusEnum = strawberry.enum(VLANStatusChoices.as_enum()) +VLANQinQRoleEnum = strawberry.enum(VLANQinQRoleChoices.as_enum()) diff --git a/netbox/ipam/graphql/filter_mixins.py b/netbox/ipam/graphql/filter_mixins.py new file mode 100644 index 00000000000..511850285a2 --- /dev/null +++ b/netbox/ipam/graphql/filter_mixins.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass +from typing import Annotated, TYPE_CHECKING + +import strawberry +import strawberry_django + +from core.graphql.filter_mixins import BaseFilterMixin + +if TYPE_CHECKING: + from netbox.graphql.filter_lookups import IntegerLookup + from .enums import * + +__all__ = ( + 'ServiceBaseFilterMixin', +) + + +@dataclass +class ServiceBaseFilterMixin(BaseFilterMixin): + protocol: Annotated['ServiceProtocolEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + ports: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) diff --git a/netbox/ipam/graphql/filters.py b/netbox/ipam/graphql/filters.py index 1b0e0133b6d..2f4e185f15e 100644 --- a/netbox/ipam/graphql/filters.py +++ b/netbox/ipam/graphql/filters.py @@ -1,7 +1,28 @@ -import strawberry_django +from datetime import date +from typing import Annotated, TYPE_CHECKING -from ipam import filtersets, models -from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin +import netaddr +import strawberry +import strawberry_django +from django.db.models import Q +from netaddr.core import AddrFormatError +from strawberry.scalars import ID +from strawberry_django import FilterLookup, DateFilterLookup + +from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin +from dcim.graphql.filter_mixins import ScopedFilterMixin +from ipam import models +from ipam.graphql.filter_mixins import ServiceBaseFilterMixin +from netbox.graphql.filter_mixins import NetBoxModelFilterMixin, OrganizationalModelFilterMixin, PrimaryModelFilterMixin +from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin + +if TYPE_CHECKING: + from netbox.graphql.filter_lookups import IntegerArrayLookup, IntegerLookup + from core.graphql.filters import ContentTypeFilter + from dcim.graphql.filters import DeviceFilter, SiteFilter + from virtualization.graphql.filters import VirtualMachineFilter + from vpn.graphql.filters import L2VPNFilter + from .enums import * __all__ = ( 'ASNFilter', @@ -26,108 +47,258 @@ __all__ = ( @strawberry_django.filter(models.ASN, lookups=True) -@autotype_decorator(filtersets.ASNFilterSet) -class ASNFilter(BaseFilterMixin): - pass +class ASNFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + rir_id: ID | None = strawberry_django.filter_field() + asn: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ASNRange, lookups=True) -@autotype_decorator(filtersets.ASNRangeFilterSet) -class ASNRangeFilter(BaseFilterMixin): - pass +class ASNRangeFilter(TenancyFilterMixin, OrganizationalModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + rir_id: ID | None = strawberry_django.filter_field() + start: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + end: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.Aggregate, lookups=True) -@autotype_decorator(filtersets.AggregateFilterSet) -class AggregateFilter(BaseFilterMixin): - pass +class AggregateFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + prefix: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + prefix_id: ID | None = strawberry_django.filter_field() + rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + rir_id: ID | None = strawberry_django.filter_field() + date_added: DateFilterLookup[date] | None = strawberry_django.filter_field() @strawberry_django.filter(models.FHRPGroup, lookups=True) -@autotype_decorator(filtersets.FHRPGroupFilterSet) -class FHRPGroupFilter(BaseFilterMixin): - pass +class FHRPGroupFilter(PrimaryModelFilterMixin): + group_id: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() + protocol: Annotated['FHRPGroupProtocolEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + auth_type: Annotated['FHRPGroupAuthTypeEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + auth_key: FilterLookup[str] | None = strawberry_django.filter_field() + ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.FHRPGroupAssignment, lookups=True) -@autotype_decorator(filtersets.FHRPGroupAssignmentFilterSet) -class FHRPGroupAssignmentFilter(BaseFilterMixin): - pass +class FHRPGroupAssignmentFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin): + interface_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + interface_id: FilterLookup[str] | None = strawberry_django.filter_field() + group: Annotated['FHRPGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + group_id: ID | None = strawberry_django.filter_field() + priority: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.IPAddress, lookups=True) -@autotype_decorator(filtersets.IPAddressFilterSet) -class IPAddressFilter(BaseFilterMixin): - pass +class IPAddressFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + address: FilterLookup[str] | None = strawberry_django.filter_field() + vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + vrf_id: ID | None = strawberry_django.filter_field() + status: Annotated['IPAddressStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + role: Annotated['IPAddressRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + assigned_object_id: ID | None = strawberry_django.filter_field() + nat_inside: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + nat_inside_id: ID | None = strawberry_django.filter_field() + nat_outside: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + nat_outside_id: ID | None = strawberry_django.filter_field() + dns_name: FilterLookup[str] | None = strawberry_django.filter_field() + + @strawberry_django.filter_field() + def parent(self, value: list[str], prefix) -> Q: + if not value: + return Q() + q = Q() + for subnet in value: + try: + query = str(netaddr.IPNetwork(subnet.strip()).cidr) + q |= Q(address__net_host_contained=query) + except (AddrFormatError, ValueError): + return Q() + return q @strawberry_django.filter(models.IPRange, lookups=True) -@autotype_decorator(filtersets.IPRangeFilterSet) -class IPRangeFilter(BaseFilterMixin): - pass +class IPRangeFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + start_address: FilterLookup[str] | None = strawberry_django.filter_field() + end_address: FilterLookup[str] | None = strawberry_django.filter_field() + size: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + vrf_id: ID | None = strawberry_django.filter_field() + status: Annotated['IPRangeStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + role: Annotated['IPAddressRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + mark_utilized: FilterLookup[bool] | None = strawberry_django.filter_field() + + @strawberry_django.filter_field() + def parent(self, value: list[str], prefix) -> Q: + if not value: + return Q() + q = Q() + for subnet in value: + try: + query = str(netaddr.IPNetwork(subnet.strip()).cidr) + q |= Q(start_address__net_host_contained=query, end_address__net_host_contained=query) + except (AddrFormatError, ValueError): + return Q() + return q @strawberry_django.filter(models.Prefix, lookups=True) -@autotype_decorator(filtersets.PrefixFilterSet) -class PrefixFilter(BaseFilterMixin): - pass +class PrefixFilter(ContactFilterMixin, ScopedFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin): + prefix: FilterLookup[str] | None = strawberry_django.filter_field() + vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + vrf_id: ID | None = strawberry_django.filter_field() + vlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + vlan_id: ID | None = strawberry_django.filter_field() + status: Annotated['PrefixStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + role: Annotated['RoleFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + role_id: ID | None = strawberry_django.filter_field() + is_pool: FilterLookup[bool] | None = strawberry_django.filter_field() + mark_utilized: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.RIR, lookups=True) -@autotype_decorator(filtersets.RIRFilterSet) -class RIRFilter(BaseFilterMixin): - pass +class RIRFilter(OrganizationalModelFilterMixin): + is_private: FilterLookup[bool] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Role, lookups=True) -@autotype_decorator(filtersets.RoleFilterSet) -class RoleFilter(BaseFilterMixin): - pass +class RoleFilter(OrganizationalModelFilterMixin): + weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.RouteTarget, lookups=True) -@autotype_decorator(filtersets.RouteTargetFilterSet) -class RouteTargetFilter(BaseFilterMixin): - pass +class RouteTargetFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.Service, lookups=True) -@autotype_decorator(filtersets.ServiceFilterSet) -class ServiceFilter(BaseFilterMixin): - pass +class ServiceFilter(ContactFilterMixin, ServiceBaseFilterMixin, PrimaryModelFilterMixin): + device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + device_id: ID | None = strawberry_django.filter_field() + virtual_machine: Annotated['VirtualMachineFilter', strawberry.lazy('virtualization.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + virtual_machine_id: ID | None = strawberry_django.filter_field() + name: FilterLookup[str] | None = strawberry_django.filter_field() + ipaddresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.ServiceTemplate, lookups=True) -@autotype_decorator(filtersets.ServiceTemplateFilterSet) -class ServiceTemplateFilter(BaseFilterMixin): - pass +class ServiceTemplateFilter(ServiceBaseFilterMixin, PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.VLAN, lookups=True) -@autotype_decorator(filtersets.VLANFilterSet) -class VLANFilter(BaseFilterMixin): - pass +class VLANFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field() + site_id: ID | None = strawberry_django.filter_field() + group: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + group_id: ID | None = strawberry_django.filter_field() + vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + name: FilterLookup[str] | None = strawberry_django.filter_field() + status: Annotated['VLANStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = strawberry_django.filter_field() + role: Annotated['RoleFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field() + role_id: ID | None = strawberry_django.filter_field() + qinq_svlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + qinq_svlan_id: ID | None = strawberry_django.filter_field() + qinq_cvlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + qinq_cvlan_id: ID | None = strawberry_django.filter_field() + qinq_role: Annotated['VLANQinQRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + l2vpn_terminations: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.VLANGroup, lookups=True) -@autotype_decorator(filtersets.VLANGroupFilterSet) -class VLANGroupFilter(BaseFilterMixin): - pass +class VLANGroupFilter(ScopedFilterMixin, OrganizationalModelFilterMixin): + vid_ranges: Annotated['IntegerArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.VLANTranslationPolicy, lookups=True) -@autotype_decorator(filtersets.VLANTranslationPolicyFilterSet) -class VLANTranslationPolicyFilter(BaseFilterMixin): - pass +class VLANTranslationPolicyFilter(PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() @strawberry_django.filter(models.VLANTranslationRule, lookups=True) -@autotype_decorator(filtersets.VLANTranslationRuleFilterSet) -class VLANTranslationRuleFilter(BaseFilterMixin): - pass +class VLANTranslationRuleFilter(NetBoxModelFilterMixin): + policy: Annotated['VLANTranslationPolicyFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + policy_id: ID | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + local_vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) + remote_vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = ( + strawberry_django.filter_field() + ) @strawberry_django.filter(models.VRF, lookups=True) -@autotype_decorator(filtersets.VRFFilterSet) -class VRFFilter(BaseFilterMixin): - pass +class VRFFilter(TenancyFilterMixin, PrimaryModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + rd: FilterLookup[str] | None = strawberry_django.filter_field() + enforce_unique: FilterLookup[bool] | None = strawberry_django.filter_field() + import_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + export_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) diff --git a/netbox/ipam/graphql/types.py b/netbox/ipam/graphql/types.py index 446ac2f2e7e..5a4c87dbee0 100644 --- a/netbox/ipam/graphql/types.py +++ b/netbox/ipam/graphql/types.py @@ -1,4 +1,4 @@ -from typing import Annotated, List, Union +from typing import Annotated, List, TYPE_CHECKING, Union import strawberry import strawberry_django @@ -11,6 +11,21 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, Organizationa from .filters import * from .mixins import IPAddressesMixin +if TYPE_CHECKING: + from dcim.graphql.types import ( + DeviceType, + InterfaceType, + LocationType, + RackType, + RegionType, + SiteGroupType, + SiteType, + ) + from tenancy.graphql.types import TenantType + from virtualization.graphql.types import ClusterGroupType, ClusterType, VMInterfaceType, VirtualMachineType + from vpn.graphql.types import L2VPNType, TunnelTerminationType + from wireless.graphql.types import WirelessLANType + __all__ = ( 'ASNType', 'ASNRangeType', @@ -55,7 +70,8 @@ class BaseIPAddressFamilyType: @strawberry_django.type( models.ASN, fields='__all__', - filters=ASNFilter + filters=ASNFilter, + pagination=True ) class ASNType(NetBoxObjectType): asn: BigInt @@ -69,7 +85,8 @@ class ASNType(NetBoxObjectType): @strawberry_django.type( models.ASNRange, fields='__all__', - filters=ASNRangeFilter + filters=ASNRangeFilter, + pagination=True ) class ASNRangeType(NetBoxObjectType): start: BigInt @@ -81,7 +98,8 @@ class ASNRangeType(NetBoxObjectType): @strawberry_django.type( models.Aggregate, fields='__all__', - filters=AggregateFilter + filters=AggregateFilter, + pagination=True ) class AggregateType(NetBoxObjectType, BaseIPAddressFamilyType): prefix: str @@ -92,7 +110,8 @@ class AggregateType(NetBoxObjectType, BaseIPAddressFamilyType): @strawberry_django.type( models.FHRPGroup, fields='__all__', - filters=FHRPGroupFilter + filters=FHRPGroupFilter, + pagination=True ) class FHRPGroupType(NetBoxObjectType, IPAddressesMixin): @@ -101,8 +120,9 @@ class FHRPGroupType(NetBoxObjectType, IPAddressesMixin): @strawberry_django.type( models.FHRPGroupAssignment, - exclude=('interface_type', 'interface_id'), - filters=FHRPGroupAssignmentFilter + exclude=['interface_type', 'interface_id'], + filters=FHRPGroupAssignmentFilter, + pagination=True ) class FHRPGroupAssignmentType(BaseObjectType): group: Annotated["FHRPGroupType", strawberry.lazy('ipam.graphql.types')] @@ -117,8 +137,9 @@ class FHRPGroupAssignmentType(BaseObjectType): @strawberry_django.type( models.IPAddress, - exclude=('assigned_object_type', 'assigned_object_id', 'address'), - filters=IPAddressFilter + exclude=['assigned_object_type', 'assigned_object_id', 'address'], + filters=IPAddressFilter, + pagination=True ) class IPAddressType(NetBoxObjectType, BaseIPAddressFamilyType): address: str @@ -143,7 +164,8 @@ class IPAddressType(NetBoxObjectType, BaseIPAddressFamilyType): @strawberry_django.type( models.IPRange, fields='__all__', - filters=IPRangeFilter + filters=IPRangeFilter, + pagination=True ) class IPRangeType(NetBoxObjectType): start_address: str @@ -155,8 +177,9 @@ class IPRangeType(NetBoxObjectType): @strawberry_django.type( models.Prefix, - exclude=('scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'), - filters=PrefixFilter + exclude=['scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'], + filters=PrefixFilter, + pagination=True ) class PrefixType(NetBoxObjectType, BaseIPAddressFamilyType): prefix: str @@ -178,7 +201,8 @@ class PrefixType(NetBoxObjectType, BaseIPAddressFamilyType): @strawberry_django.type( models.RIR, fields='__all__', - filters=RIRFilter + filters=RIRFilter, + pagination=True ) class RIRType(OrganizationalObjectType): @@ -190,7 +214,8 @@ class RIRType(OrganizationalObjectType): @strawberry_django.type( models.Role, fields='__all__', - filters=RoleFilter + filters=RoleFilter, + pagination=True ) class RoleType(OrganizationalObjectType): @@ -202,7 +227,8 @@ class RoleType(OrganizationalObjectType): @strawberry_django.type( models.RouteTarget, fields='__all__', - filters=RouteTargetFilter + filters=RouteTargetFilter, + pagination=True ) class RouteTargetType(NetBoxObjectType): tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None @@ -216,7 +242,8 @@ class RouteTargetType(NetBoxObjectType): @strawberry_django.type( models.Service, fields='__all__', - filters=ServiceFilter + filters=ServiceFilter, + pagination=True ) class ServiceType(NetBoxObjectType): ports: List[int] @@ -229,7 +256,8 @@ class ServiceType(NetBoxObjectType): @strawberry_django.type( models.ServiceTemplate, fields='__all__', - filters=ServiceTemplateFilter + filters=ServiceTemplateFilter, + pagination=True ) class ServiceTemplateType(NetBoxObjectType): ports: List[int] @@ -237,8 +265,9 @@ class ServiceTemplateType(NetBoxObjectType): @strawberry_django.type( models.VLAN, - exclude=('qinq_svlan',), - filters=VLANFilter + exclude=['qinq_svlan'], + filters=VLANFilter, + pagination=True ) class VLANType(NetBoxObjectType): site: Annotated["SiteType", strawberry.lazy('ipam.graphql.types')] | None @@ -260,13 +289,15 @@ class VLANType(NetBoxObjectType): @strawberry_django.type( models.VLANGroup, - exclude=('scope_type', 'scope_id'), - filters=VLANGroupFilter + exclude=['scope_type', 'scope_id'], + filters=VLANGroupFilter, + pagination=True ) class VLANGroupType(OrganizationalObjectType): vlans: List[VLANType] vid_ranges: List[str] + tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None @strawberry_django.field def scope(self) -> Annotated[Union[ @@ -284,7 +315,8 @@ class VLANGroupType(OrganizationalObjectType): @strawberry_django.type( models.VLANTranslationPolicy, fields='__all__', - filters=VLANTranslationPolicyFilter + filters=VLANTranslationPolicyFilter, + pagination=True ) class VLANTranslationPolicyType(NetBoxObjectType): rules: List[Annotated["VLANTranslationRuleType", strawberry.lazy('ipam.graphql.types')]] @@ -293,7 +325,8 @@ class VLANTranslationPolicyType(NetBoxObjectType): @strawberry_django.type( models.VLANTranslationRule, fields='__all__', - filters=VLANTranslationRuleFilter + filters=VLANTranslationRuleFilter, + pagination=True ) class VLANTranslationRuleType(NetBoxObjectType): policy: Annotated[ @@ -305,7 +338,8 @@ class VLANTranslationRuleType(NetBoxObjectType): @strawberry_django.type( models.VRF, fields='__all__', - filters=VRFFilter + filters=VRFFilter, + pagination=True ) class VRFType(NetBoxObjectType): tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None diff --git a/netbox/ipam/migrations/0001_squashed.py b/netbox/ipam/migrations/0001_squashed.py index 896d7c4c956..15fb71dde08 100644 --- a/netbox/ipam/migrations/0001_squashed.py +++ b/netbox/ipam/migrations/0001_squashed.py @@ -13,9 +13,9 @@ class Migration(migrations.Migration): dependencies = [ ('contenttypes', '0002_remove_content_type_name'), - ('dcim', '0002_auto_20160622_1821'), - ('extras', '0001_initial'), - ('tenancy', '0001_initial'), + ('dcim', '0002_squashed'), + ('extras', '0001_squashed'), + ('tenancy', '0001_squashed_0012'), ] replaces = [ @@ -195,12 +195,6 @@ class Migration(migrations.Migration): 'scope_type', models.ForeignKey( blank=True, - limit_choices_to=models.Q( - ( - 'model__in', - ('region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster'), - ) - ), null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', diff --git a/netbox/ipam/migrations/0002_squashed_0046.py b/netbox/ipam/migrations/0002_squashed_0046.py index 6c03753d835..43b1223d0c3 100644 --- a/netbox/ipam/migrations/0002_squashed_0046.py +++ b/netbox/ipam/migrations/0002_squashed_0046.py @@ -5,12 +5,12 @@ import taggit.managers class Migration(migrations.Migration): dependencies = [ - ('dcim', '0003_auto_20160628_1721'), - ('virtualization', '0001_virtualization'), + ('dcim', '0003_squashed_0130'), + ('virtualization', '0001_squashed_0022'), ('contenttypes', '0002_remove_content_type_name'), - ('ipam', '0001_initial'), - ('extras', '0002_custom_fields'), - ('tenancy', '0001_initial'), + ('ipam', '0001_squashed'), + ('extras', '0002_squashed_0059'), + ('tenancy', '0001_squashed_0012'), ] replaces = [ @@ -154,13 +154,6 @@ class Migration(migrations.Migration): name='assigned_object_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'dcim'), ('model', 'interface')), - models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), - _connector='OR', - ) - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', diff --git a/netbox/ipam/migrations/0047_squashed_0053.py b/netbox/ipam/migrations/0047_squashed_0053.py index a05d0cb81a4..151792eb662 100644 --- a/netbox/ipam/migrations/0047_squashed_0053.py +++ b/netbox/ipam/migrations/0047_squashed_0053.py @@ -19,7 +19,7 @@ class Migration(migrations.Migration): ] dependencies = [ - ('ipam', '0046_set_vlangroup_scope_types'), + ('ipam', '0002_squashed_0046'), ('tenancy', '0001_squashed_0012'), ('extras', '0002_squashed_0059'), ('contenttypes', '0002_remove_content_type_name'), @@ -136,14 +136,6 @@ class Migration(migrations.Migration): name='assigned_object_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'dcim'), ('model', 'interface')), - models.Q(('app_label', 'ipam'), ('model', 'fhrpgroup')), - models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), - _connector='OR', - ) - ), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', diff --git a/netbox/ipam/migrations/0054_squashed_0067.py b/netbox/ipam/migrations/0054_squashed_0067.py index 929a27fda1a..26bd5411580 100644 --- a/netbox/ipam/migrations/0054_squashed_0067.py +++ b/netbox/ipam/migrations/0054_squashed_0067.py @@ -28,11 +28,11 @@ class Migration(migrations.Migration): ] dependencies = [ - ('tenancy', '0007_contact_link'), + ('tenancy', '0002_squashed_0011'), ('contenttypes', '0002_remove_content_type_name'), ('extras', '0060_squashed_0086'), - ('ipam', '0053_asn_model'), - ('tenancy', '0009_standardize_description_comments'), + ('ipam', '0047_squashed_0053'), + ('tenancy', '0002_squashed_0011'), ] operations = [ @@ -304,14 +304,6 @@ class Migration(migrations.Migration): ( 'assigned_object_type', models.ForeignKey( - limit_choices_to=models.Q( - models.Q( - models.Q(('app_label', 'dcim'), ('model', 'interface')), - models.Q(('app_label', 'ipam'), ('model', 'vlan')), - models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), - _connector='OR', - ) - ), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype', diff --git a/netbox/ipam/migrations/0068_move_l2vpn.py b/netbox/ipam/migrations/0068_move_l2vpn.py index 9240240bc53..16935b1a61e 100644 --- a/netbox/ipam/migrations/0068_move_l2vpn.py +++ b/netbox/ipam/migrations/0068_move_l2vpn.py @@ -16,7 +16,7 @@ def update_content_types(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('ipam', '0067_ipaddress_index_host'), + ('ipam', '0054_squashed_0067'), ] operations = [ diff --git a/netbox/ipam/migrations/0071_prefix_scope.py b/netbox/ipam/migrations/0071_prefix_scope.py index 2ab54d023d0..47a9717508e 100644 --- a/netbox/ipam/migrations/0071_prefix_scope.py +++ b/netbox/ipam/migrations/0071_prefix_scope.py @@ -33,7 +33,6 @@ class Migration(migrations.Migration): name='scope_type', field=models.ForeignKey( blank=True, - limit_choices_to=models.Q(('model__in', ('region', 'sitegroup', 'site', 'location'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', diff --git a/netbox/ipam/migrations/0077_vlangroup_tenant.py b/netbox/ipam/migrations/0077_vlangroup_tenant.py new file mode 100644 index 00000000000..9fb67cf53b8 --- /dev/null +++ b/netbox/ipam/migrations/0077_vlangroup_tenant.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.3 on 2025-02-20 17:49 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ipam', '0076_natural_ordering'), + ('tenancy', '0017_natural_ordering'), + ] + + operations = [ + migrations.AddField( + model_name='vlangroup', + name='tenant', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name='vlan_groups', + to='tenancy.tenant', + ), + ), + ] diff --git a/netbox/ipam/migrations/0078_iprange_mark_utilized.py b/netbox/ipam/migrations/0078_iprange_mark_utilized.py new file mode 100644 index 00000000000..95da5387bdb --- /dev/null +++ b/netbox/ipam/migrations/0078_iprange_mark_utilized.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ipam', '0077_vlangroup_tenant'), + ] + + operations = [ + migrations.AddField( + model_name='iprange', + name='mark_populated', + field=models.BooleanField(default=False), + ), + ] diff --git a/netbox/ipam/migrations/0077_ipaddress_prefix.py b/netbox/ipam/migrations/0079_ipaddress_prefix.py similarity index 97% rename from netbox/ipam/migrations/0077_ipaddress_prefix.py rename to netbox/ipam/migrations/0079_ipaddress_prefix.py index 216fa166aee..8d3c3b67c6f 100644 --- a/netbox/ipam/migrations/0077_ipaddress_prefix.py +++ b/netbox/ipam/migrations/0079_ipaddress_prefix.py @@ -48,7 +48,7 @@ def unset_prefix(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('ipam', '0076_natural_ordering'), + ('ipam', '0078_iprange_mark_utilized'), ] operations = [ diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index 3db12f76169..f356fb8ba0f 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -383,14 +383,15 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary else: return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf) - def get_child_ranges(self): + def get_child_ranges(self, **kwargs): """ Return all IPRanges within this Prefix and VRF. """ return IPRange.objects.filter( vrf=self.vrf, start_address__net_host_contained=str(self.prefix), - end_address__net_host_contained=str(self.prefix) + end_address__net_host_contained=str(self.prefix), + **kwargs ) def get_child_ips(self): @@ -407,15 +408,14 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary """ Return all available IPs within this prefix as an IPSet. """ - if self.mark_utilized: - return netaddr.IPSet() - prefix = netaddr.IPSet(self.prefix) - child_ips = netaddr.IPSet([ip.address.ip for ip in self.ip_addresses.all()]) - child_ranges = [] - for iprange in self.get_child_ranges(): - child_ranges.append(iprange.range) - available_ips = prefix - child_ips - netaddr.IPSet(child_ranges) + child_ips = netaddr.IPSet([ + ip.address.ip for ip in self.get_child_ips() + ]) + child_ranges = netaddr.IPSet([ + iprange.range for iprange in self.get_child_ranges().filter(mark_populated=True) + ]) + available_ips = prefix - child_ips - child_ranges # IPv6 /127's, pool, or IPv4 /31-/32 sets are fully usable if (self.family == 6 and self.prefix.prefixlen >= 127) or self.is_pool or ( @@ -433,6 +433,7 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary # For IPv6 prefixes, omit the Subnet-Router anycast address # per RFC 4291 available_ips -= netaddr.IPSet([netaddr.IPAddress(self.prefix.first)]) + return available_ips def get_first_available_ip(self): @@ -461,9 +462,11 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary utilization = float(child_prefixes.size) / self.prefix.size * 100 else: # Compile an IPSet to avoid counting duplicate IPs - child_ips = netaddr.IPSet( - [_.range for _ in self.get_child_ranges()] + [_.address.ip for _ in self.ip_addresses.all()] - ) + child_ips = netaddr.IPSet() + for iprange in self.get_child_ranges().filter(mark_utilized=True): + child_ips.add(iprange.range) + for ip in self.get_child_ips(): + child_ips.add(ip.address.ip) prefix_size = self.prefix.size if self.prefix.version == 4 and self.prefix.prefixlen < 31 and not self.is_pool: @@ -519,14 +522,19 @@ class IPRange(ContactsMixin, PrimaryModel): null=True, help_text=_('The primary function of this range') ) + mark_populated = models.BooleanField( + verbose_name=_('mark populated'), + default=False, + help_text=_("Prevent the creation of IP addresses within this range") + ) mark_utilized = models.BooleanField( verbose_name=_('mark utilized'), default=False, - help_text=_("Treat as fully utilized") + help_text=_("Report space as 100% utilized") ) clone_fields = ( - 'vrf', 'tenant', 'status', 'role', 'description', + 'vrf', 'tenant', 'status', 'role', 'description', 'mark_populated', 'mark_utilized', ) class Meta: @@ -663,6 +671,9 @@ class IPRange(ContactsMixin, PrimaryModel): """ Return all available IPs within this range as an IPSet. """ + if self.mark_populated: + return netaddr.IPSet() + range = netaddr.IPRange(self.start_address.ip, self.end_address.ip) child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]) @@ -750,7 +761,6 @@ class IPAddress(ContactsMixin, PrimaryModel): ) assigned_object_type = models.ForeignKey( to='contenttypes.ContentType', - limit_choices_to=IPADDRESS_ASSIGNMENT_MODELS, on_delete=models.PROTECT, related_name='+', blank=True, @@ -889,6 +899,20 @@ class IPAddress(ContactsMixin, PrimaryModel): ) }) + # Disallow the creation of IPAddresses within an IPRange with mark_populated=True + parent_range = IPRange.objects.filter( + start_address__lte=self.address, + end_address__gte=self.address, + vrf=self.vrf, + mark_populated=True + ).first() + if parent_range: + raise ValidationError({ + 'address': _( + "Cannot create IP address {ip} inside range {range}." + ).format(ip=self.address, range=parent_range) + }) + if self._original_assigned_object_id and self._original_assigned_object_type_id: parent = getattr(self.assigned_object, 'parent_object', None) ct = ObjectType.objects.get_for_id(self._original_assigned_object_type_id) diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index 91e39c6d3b6..98491ad2380 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -45,7 +45,6 @@ class VLANGroup(OrganizationalModel): scope_type = models.ForeignKey( to='contenttypes.ContentType', on_delete=models.CASCADE, - limit_choices_to=Q(model__in=VLANGROUP_SCOPE_TYPES), blank=True, null=True ) @@ -62,6 +61,13 @@ class VLANGroup(OrganizationalModel): verbose_name=_('VLAN ID ranges'), default=default_vid_ranges ) + tenant = models.ForeignKey( + to='tenancy.Tenant', + on_delete=models.PROTECT, + related_name='vlan_groups', + blank=True, + null=True + ) _total_vlan_ids = models.PositiveBigIntegerField( default=VLAN_VID_MAX - VLAN_VID_MIN + 1 ) diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 0ad984248c9..7818e66adec 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -10,6 +10,7 @@ from .template_code import * __all__ = ( 'AggregateTable', + 'AnnotatedIPAddressTable', 'AssignedIPAddressesTable', 'IPAddressAssignTable', 'IPAddressTable', @@ -268,6 +269,10 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable): verbose_name=_('Role'), linkify=True ) + mark_populated = columns.BooleanColumn( + verbose_name=_('Marked Populated'), + false_mark=None + ) mark_utilized = columns.BooleanColumn( verbose_name=_('Marked Utilized'), false_mark=None @@ -288,7 +293,8 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable): model = IPRange fields = ( 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', - 'mark_utilized', 'utilization', 'description', 'comments', 'tags', 'created', 'last_updated', + 'mark_populated', 'mark_utilized', 'utilization', 'description', 'comments', 'tags', 'created', + 'last_updated', ) default_columns = ( 'pk', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'description', @@ -303,8 +309,8 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable): # class IPAddressTable(TenancyColumnsMixin, NetBoxTable): - address = tables.TemplateColumn( - template_code=IPADDRESS_LINK, + address = tables.Column( + linkify=True, verbose_name=_('IP Address') ) prefix = tables.Column( @@ -373,6 +379,16 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable): } +class AnnotatedIPAddressTable(IPAddressTable): + address = tables.TemplateColumn( + template_code=IPADDRESS_LINK, + verbose_name=_('IP Address') + ) + + class Meta(IPAddressTable.Meta): + pass + + class IPAddressAssignTable(NetBoxTable): address = tables.TemplateColumn( template_code=IPADDRESS_ASSIGN_LINK, diff --git a/netbox/ipam/tables/template_code.py b/netbox/ipam/tables/template_code.py index fb969345e91..cc3a344bcac 100644 --- a/netbox/ipam/tables/template_code.py +++ b/netbox/ipam/tables/template_code.py @@ -26,12 +26,12 @@ PREFIX_LINK_WITH_DEPTH = """ """ + PREFIX_LINK IPADDRESS_LINK = """ -{% if record.pk %} - {{ record.address }} +{% if record.address or record.start_address %} + {{ record }} {% elif perms.ipam.add_ipaddress %} - {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available + {{ record.title }} {% else %} - {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available + {{ record.title }} {% endif %} """ diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index aa1900e4151..c22975be09e 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -28,7 +28,7 @@ AVAILABLE_LABEL = mark_safe('Available first_ip_in_prefix: - skipped_count = int(ipaddress_list[0].address.ip - first_ip_in_prefix) - first_skipped = '{}/{}'.format(first_ip_in_prefix, prefix.prefixlen) - output.append((skipped_count, first_skipped)) + if records[0][0] > first_ip_in_prefix: + output.append(AvailableIPSpace( + size=int(records[0][0] - first_ip_in_prefix), + first_ip=f'{first_ip_in_prefix}/{prefix.mask_length}' + )) - # Iterate through existing IPs and annotate free ranges - for ip in ipaddress_list: + # Add IP ranges & addresses, annotating available space in between records + for record in records: if prev_ip: - diff = int(ip.address.ip - prev_ip.address.ip) - if diff > 1: - first_skipped = '{}/{}'.format(prev_ip.address.ip + 1, prefix.prefixlen) - output.append((diff - 1, first_skipped)) - output.append(ip) - prev_ip = ip + # Annotate available space + if (diff := int(record[0]) - int(prev_ip)) > 1: + first_skipped = f'{prev_ip + 1}/{prefix.mask_length}' + output.append(AvailableIPSpace( + size=diff - 1, + first_ip=first_skipped + )) + + output.append(record[1]) + + # Update the previous IP address + if hasattr(record[1], 'end_address'): + prev_ip = record[1].end_address.ip + else: + prev_ip = record[0] # Include any remaining available IPs - if prev_ip.address.ip < last_ip_in_prefix: - skipped_count = int(last_ip_in_prefix - prev_ip.address.ip) - first_skipped = '{}/{}'.format(prev_ip.address.ip + 1, prefix.prefixlen) - output.append((skipped_count, first_skipped)) + if prev_ip < last_ip_in_prefix: + output.append(AvailableIPSpace( + size=int(last_ip_in_prefix - prev_ip), + first_ip=f'{prev_ip + 1}/{prefix.mask_length}' + )) return output diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 944aa211ea4..75170ef6e03 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -11,7 +11,6 @@ from dcim.forms import InterfaceFilterForm from dcim.models import Interface, Site from ipam.tables import VLANTranslationRuleTable from netbox.views import generic -from tenancy.views import ObjectContactsView from utilities.query import count_related from utilities.tables import get_table_ordering from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view @@ -22,7 +21,7 @@ from . import filtersets, forms, tables from .choices import PrefixStatusChoices from .constants import * from .models import * -from .utils import add_requested_prefixes, add_available_ipaddresses, add_available_vlans +from .utils import add_requested_prefixes, add_available_vlans, annotate_ip_space # @@ -434,11 +433,6 @@ class AggregateBulkDeleteView(generic.BulkDeleteView): table = tables.AggregateTable -@register_model_view(Aggregate, 'contacts') -class AggregateContactsView(ObjectContactsView): - queryset = Aggregate.objects.all() - - # # Prefix/VLAN roles # @@ -625,7 +619,7 @@ class PrefixIPRangesView(generic.ObjectChildrenView): class PrefixIPAddressesView(generic.ObjectChildrenView): queryset = Prefix.objects.all() child_model = IPAddress - table = tables.IPAddressTable + table = tables.AnnotatedIPAddressTable filterset = filtersets.IPAddressFilterSet filterset_form = forms.IPAddressFilterForm template_name = 'ipam/prefix/ip_addresses.html' @@ -641,7 +635,7 @@ class PrefixIPAddressesView(generic.ObjectChildrenView): def prep_table_data(self, request, queryset, parent): if not request.GET.get('q') and not get_table_ordering(request, self.table): - return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool) + return annotate_ip_space(parent) return queryset def get_extra_context(self, request, instance): @@ -684,11 +678,6 @@ class PrefixBulkDeleteView(generic.BulkDeleteView): table = tables.PrefixTable -@register_model_view(Prefix, 'contacts') -class PrefixContactsView(ObjectContactsView): - queryset = Prefix.objects.all() - - # # IP Ranges # @@ -778,11 +767,6 @@ class IPRangeBulkDeleteView(generic.BulkDeleteView): table = tables.IPRangeTable -@register_model_view(IPRange, 'contacts') -class IPRangeContactsView(ObjectContactsView): - queryset = IPRange.objects.all() - - # # IP addresses # @@ -964,11 +948,6 @@ class IPAddressRelatedIPsView(generic.ObjectChildrenView): return parent.get_related_ips().restrict(request.user, 'view') -@register_model_view(IPAddress, 'contacts') -class IPAddressContactsView(ObjectContactsView): - queryset = IPAddress.objects.all() - - # # VLAN groups # @@ -1476,8 +1455,3 @@ class ServiceBulkDeleteView(generic.BulkDeleteView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') filterset = filtersets.ServiceFilterSet table = tables.ServiceTable - - -@register_model_view(Service, 'contacts') -class ServiceContactsView(ObjectContactsView): - queryset = Service.objects.all() diff --git a/netbox/netbox/api/fields.py b/netbox/netbox/api/fields.py index e7d1ef5745b..db5ec184db9 100644 --- a/netbox/netbox/api/fields.py +++ b/netbox/netbox/api/fields.py @@ -9,6 +9,7 @@ from rest_framework.exceptions import ValidationError from rest_framework.relations import PrimaryKeyRelatedField, RelatedField __all__ = ( + 'AttributesField', 'ChoiceField', 'ContentTypeField', 'IPNetworkSerializer', @@ -172,3 +173,19 @@ class IntegerRangeSerializer(serializers.Serializer): def to_representation(self, instance): return instance.lower, instance.upper - 1 + + +class AttributesField(serializers.JSONField): + """ + Custom attributes stored as JSON data. + """ + def to_internal_value(self, data): + data = super().to_internal_value(data) + + # If updating an object, start with the initial attribute data. This enables the client to modify + # individual attributes without having to rewrite the entire field. + if data and self.parent.instance: + initial_data = getattr(self.parent.instance, self.source, None) or {} + return {**initial_data, **data} + + return data diff --git a/netbox/netbox/api/views.py b/netbox/netbox/api/views.py index d58d1affe5d..1befda371f2 100644 --- a/netbox/netbox/api/views.py +++ b/netbox/netbox/api/views.py @@ -4,15 +4,15 @@ from django import __version__ as DJANGO_VERSION from django.apps import apps from django.conf import settings from django_rq.queues import get_connection -from drf_spectacular.utils import extend_schema from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import extend_schema from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.views import APIView from rq.worker import Worker -from netbox.plugins.utils import get_installed_plugins from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired +from netbox.plugins.utils import get_installed_plugins class APIRootView(APIView): @@ -66,7 +66,8 @@ class StatusView(APIView): return Response({ 'django-version': DJANGO_VERSION, 'installed-apps': installed_apps, - 'netbox-version': settings.RELEASE.full_version, + 'netbox-version': settings.RELEASE.version, + 'netbox-full-version': settings.RELEASE.full_version, 'plugins': get_installed_plugins(), 'python-version': platform.python_version(), 'rq-workers-running': Worker.count(get_connection('default')), diff --git a/netbox/netbox/api/viewsets/mixins.py b/netbox/netbox/api/viewsets/mixins.py index e07e2c78bc7..e21be234846 100644 --- a/netbox/netbox/api/viewsets/mixins.py +++ b/netbox/netbox/api/viewsets/mixins.py @@ -45,7 +45,7 @@ class ExportTemplatesMixin: if et is None: raise Http404 queryset = self.filter_queryset(self.get_queryset()) - return et.render_to_response(queryset) + return et.render_to_response(queryset=queryset) return super().list(request, *args, **kwargs) diff --git a/netbox/netbox/configuration_example.py b/netbox/netbox/configuration_example.py index 84ead53390f..27d44a2ffea 100644 --- a/netbox/netbox/configuration_example.py +++ b/netbox/netbox/configuration_example.py @@ -12,14 +12,16 @@ ALLOWED_HOSTS = [] # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: # https://docs.djangoproject.com/en/stable/ref/settings/#databases -DATABASE = { - 'ENGINE': 'django.db.backends.postgresql', # Database engine - 'NAME': 'netbox', # Database name - 'USER': '', # PostgreSQL username - 'PASSWORD': '', # PostgreSQL password - 'HOST': 'localhost', # Database server - 'PORT': '', # Database port (leave blank for default) - 'CONN_MAX_AGE': 300, # Max database connection age +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', # Database engine + 'NAME': 'netbox', # Database name + 'USER': '', # PostgreSQL username + 'PASSWORD': '', # PostgreSQL password + 'HOST': 'localhost', # Database server + 'PORT': '', # Database port (leave blank for default) + 'CONN_MAX_AGE': 300, # Max database connection age + } } # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate @@ -164,6 +166,9 @@ LOGIN_REQUIRED = True # re-authenticate. (Default: 1209600 [14 days]) LOGIN_TIMEOUT = None +# Hide the login form. Useful when only allowing SSO authentication. +LOGIN_FORM_HIDDEN = False + # The view name or URL to which users are redirected after logging out. LOGOUT_REDIRECT_URL = 'home' diff --git a/netbox/netbox/configuration_testing.py b/netbox/netbox/configuration_testing.py index cec05cabbf6..52973e94deb 100644 --- a/netbox/netbox/configuration_testing.py +++ b/netbox/netbox/configuration_testing.py @@ -5,13 +5,15 @@ ALLOWED_HOSTS = ['*'] -DATABASE = { - 'NAME': 'netbox', - 'USER': 'netbox', - 'PASSWORD': 'netbox', - 'HOST': 'localhost', - 'PORT': '', - 'CONN_MAX_AGE': 300, +DATABASES = { + 'default': { + 'NAME': 'netbox', + 'USER': 'netbox', + 'PASSWORD': 'netbox', + 'HOST': 'localhost', + 'PORT': '', + 'CONN_MAX_AGE': 300, + } } PLUGINS = [ @@ -41,6 +43,8 @@ SECRET_KEY = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' DEFAULT_PERMISSIONS = {} +ALLOW_TOKEN_RETRIEVAL = True + LOGGING = { 'version': 1, 'disable_existing_loggers': True diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index b8fbe7ad562..ffae9b7ffa8 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -1,3 +1,5 @@ +import json + import django_filters from copy import deepcopy from django.contrib.contenttypes.models import ContentType @@ -20,6 +22,7 @@ from utilities.forms.fields import MACAddressField from utilities import filters __all__ = ( + 'AttributeFiltersMixin', 'BaseFilterSet', 'ChangeLoggedModelFilterSet', 'NetBoxModelFilterSet', @@ -329,3 +332,48 @@ class OrganizationalModelFilterSet(NetBoxModelFilterSet): models.Q(slug__icontains=value) | models.Q(description__icontains=value) ) + + +class NestedGroupModelFilterSet(NetBoxModelFilterSet): + """ + A base FilterSet for models that inherit from NestedGroupModel + """ + def search(self, queryset, name, value): + if value.strip(): + queryset = queryset.filter( + models.Q(name__icontains=value) | + models.Q(slug__icontains=value) | + models.Q(description__icontains=value) | + models.Q(comments__icontains=value) + ) + + return queryset + + +class AttributeFiltersMixin: + attributes_field_name = 'attribute_data' + attribute_filter_prefix = 'attr_' + + def __init__(self, data=None, queryset=None, *, request=None, prefix=None): + self.attr_filters = {} + + # Extract JSONField-based filters from the incoming data + if data is not None: + for key, value in data.items(): + if field := self._get_field_lookup(key): + # Attempt to cast the value to a native JSON type + try: + self.attr_filters[field] = json.loads(value) + except (ValueError, json.JSONDecodeError): + self.attr_filters[field] = value + + super().__init__(data=data, queryset=queryset, request=request, prefix=prefix) + + def _get_field_lookup(self, key): + if not key.startswith(self.attribute_filter_prefix): + return + lookup = key.split(self.attribute_filter_prefix, 1)[1] # Strip prefix + return f'{self.attributes_field_name}__{lookup}' + + def filter_queryset(self, queryset): + return super().filter_queryset(queryset).filter(**self.attr_filters) diff --git a/netbox/netbox/graphql/enums.py b/netbox/netbox/graphql/enums.py new file mode 100644 index 00000000000..df62f8b3d86 --- /dev/null +++ b/netbox/netbox/graphql/enums.py @@ -0,0 +1,13 @@ +import strawberry + +from netbox.choices import * + +__all__ = ( + 'ColorEnum', + 'DistanceUnitEnum', + 'WeightUnitEnum', +) + +ColorEnum = strawberry.enum(ColorChoices.as_enum()) +DistanceUnitEnum = strawberry.enum(DistanceUnitChoices.as_enum()) +WeightUnitEnum = strawberry.enum(WeightUnitChoices.as_enum()) diff --git a/netbox/netbox/graphql/filter_lookups.py b/netbox/netbox/graphql/filter_lookups.py new file mode 100644 index 00000000000..859236e4d25 --- /dev/null +++ b/netbox/netbox/graphql/filter_lookups.py @@ -0,0 +1,219 @@ +from enum import Enum +from typing import TypeVar, Tuple, Generic + +import strawberry +import strawberry_django +from django.core.exceptions import FieldDoesNotExist +from django.db.models import Q, QuerySet +from django.db.models.fields.related import ForeignKey, ManyToManyField, ManyToManyRel, ManyToOneRel +from strawberry import ID +from strawberry.types import Info +from strawberry_django import ( + ComparisonFilterLookup, + DateFilterLookup, + DatetimeFilterLookup, + FilterLookup, + RangeLookup, + TimeFilterLookup, + process_filters, +) + +__all__ = ( + 'ArrayLookup', + 'FloatArrayLookup', + 'FloatLookup', + 'IntegerArrayLookup', + 'IntegerLookup', + 'JSONFilter', + 'StringArrayLookup', + 'TreeNodeFilter', +) + +T = TypeVar('T') +SKIP_MSG = 'Filter will be skipped on `null` value' + + +@strawberry.input(one_of=True, description='Lookup for JSON field. Only one of the lookup fields can be set.') +class JSONLookup: + string_lookup: FilterLookup[str] | None = strawberry_django.filter_field() + int_range_lookup: RangeLookup[int] | None = strawberry_django.filter_field() + int_comparison_lookup: ComparisonFilterLookup[int] | None = strawberry_django.filter_field() + float_range_lookup: RangeLookup[float] | None = strawberry_django.filter_field() + float_comparison_lookup: ComparisonFilterLookup[float] | None = strawberry_django.filter_field() + date_lookup: DateFilterLookup[str] | None = strawberry_django.filter_field() + datetime_lookup: DatetimeFilterLookup[str] | None = strawberry_django.filter_field() + time_lookup: TimeFilterLookup[str] | None = strawberry_django.filter_field() + boolean_lookup: FilterLookup[bool] | None = strawberry_django.filter_field() + + def get_filter(self): + for field in self.__strawberry_definition__.fields: + value = getattr(self, field.name, None) + if value is not strawberry.UNSET: + return value + return None + + +@strawberry.input(one_of=True, description='Lookup for Integer fields. Only one of the lookup fields can be set.') +class IntegerLookup: + filter_lookup: FilterLookup[int] | None = strawberry_django.filter_field() + range_lookup: RangeLookup[int] | None = strawberry_django.filter_field() + comparison_lookup: ComparisonFilterLookup[int] | None = strawberry_django.filter_field() + + def get_filter(self): + for field in self.__strawberry_definition__.fields: + value = getattr(self, field.name, None) + if value is not strawberry.UNSET: + return value + return None + + @strawberry_django.filter_field + def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]: + filters = self.get_filter() + + if not filters: + return queryset, Q() + + return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix) + + +@strawberry.input(one_of=True, description='Lookup for Float fields. Only one of the lookup fields can be set.') +class FloatLookup: + filter_lookup: FilterLookup[float] | None = strawberry_django.filter_field() + range_lookup: RangeLookup[float] | None = strawberry_django.filter_field() + comparison_lookup: ComparisonFilterLookup[float] | None = strawberry_django.filter_field() + + def get_filter(self): + for field in self.__strawberry_definition__.fields: + value = getattr(self, field.name, None) + if value is not strawberry.UNSET: + return value + return None + + @strawberry_django.filter_field + def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]: + filters = self.get_filter() + + if not filters: + return queryset, Q() + + return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix) + + +@strawberry.input +class JSONFilter: + """ + Class for JSON field lookups with paths + """ + + path: str + lookup: JSONLookup + + @strawberry_django.filter_field + def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]: + filters = self.lookup.get_filter() + + if not filters: + return queryset, Q() + + json_path = f'{prefix}{self.path}__' + return process_filters(filters=filters, queryset=queryset, info=info, prefix=json_path) + + +@strawberry.enum +class TreeNodeMatch(Enum): + EXACT = 'exact' # Just the node itself + DESCENDANTS = 'descendants' # Node and all descendants + SELF_AND_DESCENDANTS = 'self_and_descendants' # Node and all descendants + CHILDREN = 'children' # Just immediate children + SIBLINGS = 'siblings' # Nodes with same parent + ANCESTORS = 'ancestors' # All parent nodes + PARENT = 'parent' # Just immediate parent + + +@strawberry.input +class TreeNodeFilter: + id: ID + match_type: TreeNodeMatch + + @strawberry_django.filter_field + def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]: + model_field_name = prefix.removesuffix('__').removesuffix('_id') + model_field = None + try: + model_field = queryset.model._meta.get_field(model_field_name) + except FieldDoesNotExist: + try: + model_field = queryset.model._meta.get_field(f'{model_field_name}s') + except FieldDoesNotExist: + return queryset, Q(pk__in=[]) + + if hasattr(model_field, 'related_model'): + related_model = model_field.related_model + else: + return queryset, Q(pk__in=[]) + + # Generate base Q filter for the related model without prefix + q_filter = generate_tree_node_q_filter(related_model, self) + + # Handle different relationship types + if isinstance(model_field, (ManyToManyField, ManyToManyRel)): + return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)}) + elif isinstance(model_field, ForeignKey): + return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children}) + elif isinstance(model_field, ManyToOneRel): + return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)}) + else: + return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children}) + + +def generate_tree_node_q_filter(model_class, filter_value: TreeNodeFilter) -> Q: + """ + Generate appropriate Q filter for MPTT tree filtering based on match type + """ + try: + node = model_class.objects.get(id=filter_value.id) + except model_class.DoesNotExist: + return Q(pk__in=[]) + + if filter_value.match_type == TreeNodeMatch.EXACT: + return Q(id=filter_value.id) + elif filter_value.match_type == TreeNodeMatch.DESCENDANTS: + return Q(tree_id=node.tree_id, lft__gt=node.lft, rght__lt=node.rght) + elif filter_value.match_type == TreeNodeMatch.SELF_AND_DESCENDANTS: + return Q(tree_id=node.tree_id, lft__gte=node.lft, rght__lte=node.rght) + elif filter_value.match_type == TreeNodeMatch.CHILDREN: + return Q(tree_id=node.tree_id, level=node.level + 1, lft__gt=node.lft, rght__lt=node.rght) + elif filter_value.match_type == TreeNodeMatch.SIBLINGS: + return Q(tree_id=node.tree_id, level=node.level, parent=node.parent) & ~Q(id=node.id) + elif filter_value.match_type == TreeNodeMatch.ANCESTORS: + return Q(tree_id=node.tree_id, lft__lt=node.lft, rght__gt=node.rght) + elif filter_value.match_type == TreeNodeMatch.PARENT: + return Q(id=node.parent_id) if node.parent_id else Q(pk__in=[]) + return Q() + + +@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.') +class ArrayLookup(Generic[T]): + """ + Class for Array field lookups + """ + + contains: list[T] | None = strawberry_django.filter_field(description='Contains the value') + contained_by: list[T] | None = strawberry_django.filter_field(description='Contained by the value') + overlap: list[T] | None = strawberry_django.filter_field(description='Overlaps with the value') + length: int | None = strawberry_django.filter_field(description='Length of the array') + + +@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.') +class IntegerArrayLookup(ArrayLookup[int]): + pass + + +@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.') +class FloatArrayLookup(ArrayLookup[float]): + pass + + +@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.') +class StringArrayLookup(ArrayLookup[str]): + pass diff --git a/netbox/netbox/graphql/filter_mixins.py b/netbox/netbox/graphql/filter_mixins.py index 2044a1ddeeb..ce6d81a8690 100644 --- a/netbox/netbox/graphql/filter_mixins.py +++ b/netbox/netbox/graphql/filter_mixins.py @@ -1,209 +1,109 @@ -from functools import partialmethod -from typing import List +from dataclasses import dataclass +from datetime import datetime +from typing import TypeVar, TYPE_CHECKING, Annotated -import django_filters import strawberry import strawberry_django -from django.core.exceptions import FieldDoesNotExist -from strawberry import auto +from strawberry import ID +from strawberry_django import FilterLookup, DatetimeFilterLookup -from ipam.fields import ASNField -from netbox.graphql.scalars import BigInt -from utilities.fields import ColorField, CounterCacheField -from utilities.filters import * +from core.graphql.filter_mixins import BaseFilterMixin, BaseObjectTypeFilterMixin, ChangeLogFilterMixin +from extras.graphql.filter_mixins import CustomFieldsFilterMixin, JournalEntriesFilterMixin, TagsFilterMixin +from netbox.graphql.filter_lookups import IntegerLookup + +__all__ = ( + 'DistanceFilterMixin', + 'ImageAttachmentFilterMixin', + 'NestedGroupModelFilterMixin', + 'NetBoxModelFilterMixin', + 'OrganizationalModelFilterMixin', + 'PrimaryModelFilterMixin', + 'SyncedDataFilterMixin', + 'WeightFilterMixin', +) + +T = TypeVar('T') -def map_strawberry_type(field): - should_create_function = False - attr_type = None - - # NetBox Filter types - put base classes after derived classes - if isinstance(field, ContentTypeFilter): - should_create_function = True - attr_type = str | None - elif isinstance(field, MultiValueArrayFilter): - pass - elif isinstance(field, MultiValueCharFilter): - # Note: Need to use the legacy FilterLookup from filters, not from - # strawberry_django.FilterLookup as we currently have USE_DEPRECATED_FILTERS - attr_type = strawberry_django.filters.FilterLookup[str] | None - elif isinstance(field, MultiValueDateFilter): - attr_type = auto - elif isinstance(field, MultiValueDateTimeFilter): - attr_type = auto - elif isinstance(field, MultiValueDecimalFilter): - pass - elif isinstance(field, MultiValueMACAddressFilter): - should_create_function = True - attr_type = List[str] | None - elif isinstance(field, MultiValueNumberFilter): - should_create_function = True - attr_type = List[str] | None - elif isinstance(field, MultiValueTimeFilter): - pass - elif isinstance(field, MultiValueWWNFilter): - should_create_function = True - attr_type = List[str] | None - elif isinstance(field, NullableCharFieldFilter): - pass - elif isinstance(field, NumericArrayFilter): - should_create_function = True - attr_type = int | None - elif isinstance(field, TreeNodeMultipleChoiceFilter): - should_create_function = True - attr_type = List[str] | None - - # From django_filters - ordering of these matters as base classes must - # come after derived classes so the base class doesn't get matched first - # a pass for the check (no attr_type) means we don't currently handle - # or use that type - elif issubclass(type(field), django_filters.OrderingFilter): - pass - elif issubclass(type(field), django_filters.BaseRangeFilter): - pass - elif issubclass(type(field), django_filters.BaseInFilter): - pass - elif issubclass(type(field), django_filters.LookupChoiceFilter): - pass - elif issubclass(type(field), django_filters.AllValuesMultipleFilter): - pass - elif issubclass(type(field), django_filters.AllValuesFilter): - pass - elif issubclass(type(field), django_filters.TimeRangeFilter): - pass - elif issubclass(type(field), django_filters.IsoDateTimeFromToRangeFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.DateTimeFromToRangeFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.DateFromToRangeFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.DateRangeFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.RangeFilter): - pass - elif issubclass(type(field), django_filters.NumericRangeFilter): - pass - elif issubclass(type(field), django_filters.NumberFilter): - should_create_function = True - attr_type = int | None - elif issubclass(type(field), django_filters.ModelMultipleChoiceFilter): - should_create_function = True - attr_type = List[str] | None - elif issubclass(type(field), django_filters.ModelChoiceFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.DurationFilter): - pass - elif issubclass(type(field), django_filters.IsoDateTimeFilter): - pass - elif issubclass(type(field), django_filters.DateTimeFilter): - attr_type = auto - elif issubclass(type(field), django_filters.TimeFilter): - attr_type = auto - elif issubclass(type(field), django_filters.DateFilter): - attr_type = auto - elif issubclass(type(field), django_filters.TypedMultipleChoiceFilter): - pass - elif issubclass(type(field), django_filters.MultipleChoiceFilter): - attr_type = str | None - elif issubclass(type(field), django_filters.TypedChoiceFilter): - pass - elif issubclass(type(field), django_filters.ChoiceFilter): - pass - elif issubclass(type(field), django_filters.BooleanFilter): - should_create_function = True - attr_type = bool | None - elif issubclass(type(field), django_filters.UUIDFilter): - should_create_function = True - attr_type = str | None - elif issubclass(type(field), django_filters.CharFilter): - # looks like only used by 'q' - should_create_function = True - attr_type = str | None - - return should_create_function, attr_type +if TYPE_CHECKING: + from .enums import * + from core.graphql.filters import * + from extras.graphql.filters import * -def autotype_decorator(filterset): - """ - Decorator used to auto creates a dataclass used by Strawberry based on a filterset. - Must go after the Strawberry decorator as follows: - - @strawberry_django.filter(models.Example, lookups=True) - @autotype_decorator(filtersets.ExampleFilterSet) - class ExampleFilter(BaseFilterMixin): - pass - - The Filter itself must be derived from BaseFilterMixin. For items listed in meta.fields - of the filterset, usually just a type specifier is generated, so for - `fields = [created, ]` the dataclass would be: - - class ExampleFilter(BaseFilterMixin): - created: auto - - For other filter fields a function needs to be created for Strawberry with the - naming convention `filter_{fieldname}` which is auto detected and called by - Strawberry, this function uses the filterset to handle the query. - """ - def create_attribute_and_function(cls, fieldname, attr_type, should_create_function): - if fieldname not in cls.__annotations__ and attr_type: - cls.__annotations__[fieldname] = attr_type - - filter_name = f"filter_{fieldname}" - if should_create_function and not hasattr(cls, filter_name): - filter_by_filterset = getattr(cls, 'filter_by_filterset') - setattr(cls, filter_name, partialmethod(filter_by_filterset, key=fieldname)) - - def wrapper(cls): - cls.filterset = filterset - fields = filterset.get_fields() - model = filterset._meta.model - for fieldname in fields.keys(): - should_create_function = False - attr_type = auto - if fieldname not in cls.__annotations__: - try: - field = model._meta.get_field(fieldname) - except FieldDoesNotExist: - continue - - if isinstance(field, CounterCacheField): - should_create_function = True - attr_type = BigInt | None - elif isinstance(field, ASNField): - should_create_function = True - attr_type = List[str] | None - elif isinstance(field, ColorField): - should_create_function = True - attr_type = List[str] | None - - create_attribute_and_function(cls, fieldname, attr_type, should_create_function) - - declared_filters = filterset.declared_filters - for fieldname, field in declared_filters.items(): - - should_create_function, attr_type = map_strawberry_type(field) - if attr_type is None: - raise NotImplementedError(f"GraphQL Filter field unknown: {fieldname}: {field}") - - create_attribute_and_function(cls, fieldname, attr_type, should_create_function) - - return cls - - return wrapper +class NetBoxModelFilterMixin( + ChangeLogFilterMixin, + CustomFieldsFilterMixin, + JournalEntriesFilterMixin, + TagsFilterMixin, + BaseObjectTypeFilterMixin, +): + pass -@strawberry.input -class BaseFilterMixin: +@dataclass +class NestedGroupModelFilterMixin(NetBoxModelFilterMixin): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + lft: IntegerLookup | None = strawberry_django.filter_field() + rght: IntegerLookup | None = strawberry_django.filter_field() + tree_id: IntegerLookup | None = strawberry_django.filter_field() + level: IntegerLookup | None = strawberry_django.filter_field() + parent_id: ID | None = strawberry_django.filter_field() - def filter_by_filterset(self, queryset, key): - filterset = self.filterset(data={key: getattr(self, key)}, queryset=queryset) - if not filterset.is_valid(): - # We could raise validation error but strawberry logs it all to the - # console i.e. raise ValidationError(f"{k}: {v[0]}") - return filterset.qs.none() - return filterset.qs + +@dataclass +class OrganizationalModelFilterMixin( + ChangeLogFilterMixin, + CustomFieldsFilterMixin, + TagsFilterMixin, + BaseObjectTypeFilterMixin, +): + name: FilterLookup[str] | None = strawberry_django.filter_field() + slug: FilterLookup[str] | None = strawberry_django.filter_field() + description: FilterLookup[str] | None = strawberry_django.filter_field() + + +@dataclass +class PrimaryModelFilterMixin(NetBoxModelFilterMixin): + description: FilterLookup[str] | None = strawberry_django.filter_field() + comments: FilterLookup[str] | None = strawberry_django.filter_field() + + +@dataclass +class ImageAttachmentFilterMixin(BaseFilterMixin): + images: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class WeightFilterMixin(BaseFilterMixin): + weight: FilterLookup[float] | None = strawberry_django.filter_field() + weight_unit: Annotated['WeightUnitEnum', strawberry.lazy('netbox.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) + + +@dataclass +class SyncedDataFilterMixin(BaseFilterMixin): + data_source: Annotated['DataSourceFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + data_source_id: FilterLookup[int] | None = strawberry_django.filter_field() + data_file: Annotated['DataFileFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + data_file_id: FilterLookup[int] | None = strawberry_django.filter_field() + data_path: FilterLookup[str] | None = strawberry_django.filter_field() + auto_sync_enabled: FilterLookup[bool] | None = strawberry_django.filter_field() + data_synced: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + + +@dataclass +class DistanceFilterMixin(BaseFilterMixin): + distance: FilterLookup[float] | None = strawberry_django.filter_field() + distance_unit: Annotated['DistanceUnitEnum', strawberry.lazy('netbox.graphql.enums')] | None = ( + strawberry_django.filter_field() + ) diff --git a/netbox/netbox/graphql/schema.py b/netbox/netbox/graphql/schema.py index a7609c9d206..c840e769cf9 100644 --- a/netbox/netbox/graphql/schema.py +++ b/netbox/netbox/graphql/schema.py @@ -1,7 +1,7 @@ import strawberry from django.conf import settings from strawberry_django.optimizer import DjangoOptimizerExtension -from strawberry.extensions import MaxAliasesLimiter +from strawberry.extensions import MaxAliasesLimiter # , SchemaExtension from strawberry.schema.config import StrawberryConfig from circuits.graphql.schema import CircuitsQuery diff --git a/netbox/netbox/graphql/types.py b/netbox/netbox/graphql/types.py index a4fc9908072..65346263014 100644 --- a/netbox/netbox/graphql/types.py +++ b/netbox/netbox/graphql/types.py @@ -8,6 +8,7 @@ from extras.graphql.mixins import CustomFieldsMixin, JournalEntriesMixin, TagsMi __all__ = ( 'BaseObjectType', + 'ContentTypeType', 'ObjectType', 'OrganizationalObjectType', 'NetBoxObjectType', @@ -83,6 +84,7 @@ class NetBoxObjectType( @strawberry_django.type( ContentType, fields=['id', 'app_label', 'model'], + pagination=True ) class ContentTypeType: pass @@ -91,6 +93,7 @@ class ContentTypeType: @strawberry_django.type( ObjectType_, fields=['id', 'app_label', 'model'], + pagination=True ) class ObjectTypeType: pass diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py index b9424bd7ca1..714c20e5648 100644 --- a/netbox/netbox/middleware.py +++ b/netbox/netbox/middleware.py @@ -2,6 +2,7 @@ from contextlib import ExitStack import logging import uuid +import warnings from django.conf import settings from django.contrib import auth, messages @@ -37,7 +38,10 @@ class CoreMiddleware: # Apply all registered request processors with ExitStack() as stack: for request_processor in registry['request_processors']: - stack.enter_context(request_processor(request)) + try: + stack.enter_context(request_processor(request)) + except Exception as e: + warnings.warn(f'Failed to initialize request processor {request_processor}: {e}') response = self.get_response(request) # Check if language cookie should be renewed @@ -94,18 +98,23 @@ class RemoteUserMiddleware(RemoteUserMiddleware_): """ Custom implementation of Django's RemoteUserMiddleware which allows for a user-configurable HTTP header name. """ + async_capable = False force_logout_if_no_header = False + def __init__(self, get_response): + if get_response is None: + raise ValueError("get_response must be provided.") + self.get_response = get_response + @property def header(self): return settings.REMOTE_AUTH_HEADER - def process_request(self, request): - logger = logging.getLogger( - 'netbox.authentication.RemoteUserMiddleware') + def __call__(self, request): + logger = logging.getLogger('netbox.authentication.RemoteUserMiddleware') # Bypass middleware if remote authentication is not enabled if not settings.REMOTE_AUTH_ENABLED: - return + return self.get_response(request) # AuthenticationMiddleware is required so that request.user exists. if not hasattr(request, 'user'): raise ImproperlyConfigured( @@ -122,13 +131,13 @@ class RemoteUserMiddleware(RemoteUserMiddleware_): # AnonymousUser by the AuthenticationMiddleware). if self.force_logout_if_no_header and request.user.is_authenticated: self._remove_invalid_user(request) - return + return self.get_response(request) # If the user is already authenticated and that user is the user we are # getting passed in the headers, then the correct user is already # persisted in the session and we don't need to continue. if request.user.is_authenticated: if request.user.get_username() == self.clean_username(username, request): - return + return self.get_response(request) else: # An authenticated user is associated with the request, but # it does not match the authorized user in the header. @@ -158,6 +167,8 @@ class RemoteUserMiddleware(RemoteUserMiddleware_): request.user = user auth.login(request, user) + return self.get_response(request) + def _get_groups(self, request): logger = logging.getLogger( 'netbox.authentication.RemoteUserMiddleware') diff --git a/netbox/netbox/models/__init__.py b/netbox/netbox/models/__init__.py index b1f7cfd4891..3ad0ac556ba 100644 --- a/netbox/netbox/models/__init__.py +++ b/netbox/netbox/models/__init__.py @@ -150,6 +150,10 @@ class NestedGroupModel(NetBoxFeatureSet, MPTTModel): max_length=200, blank=True ) + comments = models.TextField( + verbose_name=_('comments'), + blank=True + ) objects = TreeManager() diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index a972277705c..55093e69d34 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -5,6 +5,7 @@ from functools import cached_property from django.contrib.contenttypes.fields import GenericRelation from django.core.validators import ValidationError from django.db import models +from django.db.models import Q from django.utils import timezone from django.utils.translation import gettext_lazy as _ from taggit.managers import TaggableManager @@ -19,7 +20,6 @@ from netbox.registry import registry from netbox.signals import post_clean from utilities.json import CustomFieldJSONEncoder from utilities.serialization import serialize_object -from utilities.views import register_model_view __all__ = ( 'BookmarksMixin', @@ -352,7 +352,7 @@ class ImageAttachmentsMixin(models.Model): class ContactsMixin(models.Model): """ - Enables the assignments of Contacts (via ContactAssignment). + Enables the assignment of Contacts to a model (via ContactAssignment). """ contacts = GenericRelation( to='tenancy.ContactAssignment', @@ -363,6 +363,27 @@ class ContactsMixin(models.Model): class Meta: abstract = True + def get_contacts(self, inherited=True): + """ + Return a `QuerySet` matching all contacts assigned to this object. + + Args: + inherited: If `True`, inherited contacts from parent objects are included. + """ + from tenancy.models import ContactAssignment + from . import NestedGroupModel + + filter = Q( + object_type=ObjectType.objects.get_for_model(self), + object_id__in=( + self.get_ancestors(include_self=True) + if (isinstance(self, NestedGroupModel) and inherited) + else [self.pk] + ), + ) + + return ContactAssignment.objects.filter(filter) + class BookmarksMixin(models.Model): """ @@ -434,7 +455,8 @@ class TagsMixin(models.Model): which is a `TaggableManager` instance. """ tags = TaggableManager( - through='extras.TaggedItem' + through='extras.TaggedItem', + ordering=('weight', 'name'), ) class Meta: @@ -617,6 +639,8 @@ def register_models(*models): register_model() should be called for each relevant model under the ready() of an app's AppConfig class. """ + from utilities.views import register_model_view + for model in models: app_label, model_name = model._meta.label_lower.split('.') @@ -637,6 +661,10 @@ def register_models(*models): ) # Register applicable feature views for the model + if issubclass(model, ContactsMixin): + register_model_view(model, 'contacts', kwargs={'model': model})( + 'netbox.views.generic.ObjectContactsView' + ) if issubclass(model, JournalingMixin): register_model_view(model, 'journal', kwargs={'model': model})( 'netbox.views.generic.ObjectJournalView' diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index 9148caa8e8c..778f0d67cc0 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -85,6 +85,7 @@ DEVICES_MENU = Menu( items=( get_model_item('dcim', 'devicetype', _('Device Types')), get_model_item('dcim', 'moduletype', _('Module Types')), + get_model_item('dcim', 'moduletypeprofile', _('Module Type Profiles')), get_model_item('dcim', 'manufacturer', _('Manufacturers')), ), ), diff --git a/netbox/netbox/plugins/__init__.py b/netbox/netbox/plugins/__init__.py index bb3280ac4e8..b7bb0ef9fa2 100644 --- a/netbox/netbox/plugins/__init__.py +++ b/netbox/netbox/plugins/__init__.py @@ -6,6 +6,7 @@ from django.core.exceptions import ImproperlyConfigured from django.utils.module_loading import import_string from packaging import version +from core.exceptions import IncompatiblePluginError from netbox.registry import registry from netbox.search import register_search from netbox.utils import register_data_backend @@ -140,14 +141,14 @@ class PluginConfig(AppConfig): if cls.min_version is not None: min_version = version.parse(cls.min_version) if current_version < min_version: - raise ImproperlyConfigured( + raise IncompatiblePluginError( f"Plugin {cls.__module__} requires NetBox minimum version {cls.min_version} (current: " f"{netbox_version})." ) if cls.max_version is not None: max_version = version.parse(cls.max_version) if current_version > max_version: - raise ImproperlyConfigured( + raise IncompatiblePluginError( f"Plugin {cls.__module__} requires NetBox maximum version {cls.max_version} (current: " f"{netbox_version})." ) diff --git a/netbox/netbox/plugins/registration.py b/netbox/netbox/plugins/registration.py index 515405f1b3c..0001d50c920 100644 --- a/netbox/netbox/plugins/registration.py +++ b/netbox/netbox/plugins/registration.py @@ -1,7 +1,7 @@ import inspect -import warnings from django.utils.translation import gettext_lazy as _ + from netbox.registry import registry from .navigation import PluginMenu, PluginMenuButton, PluginMenuItem from .templates import PluginTemplateExtension @@ -35,16 +35,8 @@ def register_template_extensions(class_list): ) if template_extension.models: - # Registration for multiple models + # Registration for specific models models = template_extension.models - elif template_extension.model: - # Registration for a single model (deprecated) - warnings.warn( - "PluginTemplateExtension.model is deprecated and will be removed in a future release. Use " - "'models' instead.", - DeprecationWarning - ) - models = [template_extension.model] else: # Global registration (no specific models) models = [None] diff --git a/netbox/netbox/plugins/templates.py b/netbox/netbox/plugins/templates.py index 4ea90b4db0c..586391d4fb9 100644 --- a/netbox/netbox/plugins/templates.py +++ b/netbox/netbox/plugins/templates.py @@ -11,8 +11,14 @@ class PluginTemplateExtension: This class is used to register plugin content to be injected into core NetBox templates. It contains methods that are overridden by plugin authors to return template content. - The `model` attribute on the class defines the which model detail page this class renders content for. It - should be set as a string in the form '.'. render() provides the following context data: + The `models` attribute on the class defines the which specific model detail pages this class renders content + for. It should be defined as a list of strings in the following form: + + models = ['.', '.'] + + If `models` is left as None, the extension will render for _all_ models. + + The `render()` method provides the following context data: * object - The object being viewed (object views only) * model - The type of object being viewed (list views only) @@ -21,7 +27,6 @@ class PluginTemplateExtension: * config - Plugin-specific configuration parameters """ models = None - model = None # Deprecated; use `models` instead def __init__(self, context): self.context = context @@ -42,6 +47,13 @@ class PluginTemplateExtension: # Global methods # + def head(self): + """ + HTML returned by this method will be inserted in the page's `` block. This may be useful e.g. for + including additional Javascript or CSS resources. + """ + raise NotImplementedError + def navbar(self): """ Content that will be rendered inside the top navigation menu. Content should be returned as an HTML diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a17bb77305e..c453817d0d5 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -9,12 +9,15 @@ import warnings from django.contrib.messages import constants as messages from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.validators import URLValidator +from django.utils.module_loading import import_string from django.utils.translation import gettext_lazy as _ +from core.exceptions import IncompatiblePluginError from netbox.config import PARAMS as CONFIG_PARAMS from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW from netbox.plugins import PluginConfig from netbox.registry import registry +import storages.utils # type: ignore from utilities.release import load_release_data from utilities.string import trailing_slash @@ -50,14 +53,18 @@ except ModuleNotFoundError as e: ) raise -# Check for missing required configuration parameters -for parameter in ('ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY', 'REDIS'): +# Check for missing/conflicting required configuration parameters +for parameter in ('ALLOWED_HOSTS', 'SECRET_KEY', 'REDIS'): if not hasattr(configuration, parameter): raise ImproperlyConfigured(f"Required parameter {parameter} is missing from configuration.") +if not hasattr(configuration, 'DATABASE') and not hasattr(configuration, 'DATABASES'): + raise ImproperlyConfigured("The database configuration must be defined using DATABASE or DATABASES.") +elif hasattr(configuration, 'DATABASE') and hasattr(configuration, 'DATABASES'): + raise ImproperlyConfigured("DATABASE and DATABASES may not be set together. The use of DATABASES is encouraged.") # Set static config parameters ADMINS = getattr(configuration, 'ADMINS', []) -ALLOW_TOKEN_RETRIEVAL = getattr(configuration, 'ALLOW_TOKEN_RETRIEVAL', True) +ALLOW_TOKEN_RETRIEVAL = getattr(configuration, 'ALLOW_TOKEN_RETRIEVAL', False) ALLOWED_HOSTS = getattr(configuration, 'ALLOWED_HOSTS') # Required AUTH_PASSWORD_VALIDATORS = getattr(configuration, 'AUTH_PASSWORD_VALIDATORS', [ { @@ -81,7 +88,9 @@ CSRF_COOKIE_PATH = f'/{BASE_PATH.rstrip("/")}' CSRF_COOKIE_SECURE = getattr(configuration, 'CSRF_COOKIE_SECURE', False) CSRF_TRUSTED_ORIGINS = getattr(configuration, 'CSRF_TRUSTED_ORIGINS', []) DATA_UPLOAD_MAX_MEMORY_SIZE = getattr(configuration, 'DATA_UPLOAD_MAX_MEMORY_SIZE', 2621440) -DATABASE = getattr(configuration, 'DATABASE') # Required +DATABASE = getattr(configuration, 'DATABASE', None) # Legacy DB definition +DATABASE_ROUTERS = getattr(configuration, 'DATABASE_ROUTERS', []) +DATABASES = getattr(configuration, 'DATABASES', {'default': DATABASE}) DEBUG = getattr(configuration, 'DEBUG', False) DEFAULT_DASHBOARD = getattr(configuration, 'DEFAULT_DASHBOARD', None) DEFAULT_PERMISSIONS = getattr(configuration, 'DEFAULT_PERMISSIONS', { @@ -116,7 +125,7 @@ EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', []) FIELD_CHOICES = getattr(configuration, 'FIELD_CHOICES', {}) FILE_UPLOAD_MAX_MEMORY_SIZE = getattr(configuration, 'FILE_UPLOAD_MAX_MEMORY_SIZE', 2621440) GRAPHQL_MAX_ALIASES = getattr(configuration, 'GRAPHQL_MAX_ALIASES', 10) -HTTP_PROXIES = getattr(configuration, 'HTTP_PROXIES', None) +HTTP_PROXIES = getattr(configuration, 'HTTP_PROXIES', {}) INTERNAL_IPS = getattr(configuration, 'INTERNAL_IPS', ('127.0.0.1', '::1')) ISOLATED_DEPLOYMENT = getattr(configuration, 'ISOLATED_DEPLOYMENT', False) JINJA2_FILTERS = getattr(configuration, 'JINJA2_FILTERS', {}) @@ -126,11 +135,14 @@ LOGGING = getattr(configuration, 'LOGGING', {}) LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', True) LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) +LOGIN_FORM_HIDDEN = getattr(configuration, 'LOGIN_FORM_HIDDEN', False) LOGOUT_REDIRECT_URL = getattr(configuration, 'LOGOUT_REDIRECT_URL', 'home') MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/') METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False) PLUGINS = getattr(configuration, 'PLUGINS', []) PLUGINS_CONFIG = getattr(configuration, 'PLUGINS_CONFIG', {}) +PLUGINS_CATALOG_CONFIG = getattr(configuration, 'PLUGINS_CATALOG_CONFIG', {}) +PROXY_ROUTERS = getattr(configuration, 'PROXY_ROUTERS', ['utilities.proxy.DefaultProxyRouter']) QUEUE_MAPPINGS = getattr(configuration, 'QUEUE_MAPPINGS', {}) REDIS = getattr(configuration, 'REDIS') # Required RELEASE_CHECK_URL = getattr(configuration, 'RELEASE_CHECK_URL', None) @@ -174,7 +186,8 @@ SESSION_COOKIE_PATH = CSRF_COOKIE_PATH SESSION_COOKIE_SECURE = getattr(configuration, 'SESSION_COOKIE_SECURE', False) SESSION_FILE_PATH = getattr(configuration, 'SESSION_FILE_PATH', None) STORAGE_BACKEND = getattr(configuration, 'STORAGE_BACKEND', None) -STORAGE_CONFIG = getattr(configuration, 'STORAGE_CONFIG', {}) +STORAGE_CONFIG = getattr(configuration, 'STORAGE_CONFIG', None) +STORAGES = getattr(configuration, 'STORAGES', {}) TIME_ZONE = getattr(configuration, 'TIME_ZONE', 'UTC') TRANSLATION_ENABLED = getattr(configuration, 'TRANSLATION_ENABLED', True) @@ -201,83 +214,92 @@ if RELEASE_CHECK_URL: "RELEASE_CHECK_URL must be a valid URL. Example: https://api.github.com/repos/netbox-community/netbox" ) +# Validate configured proxy routers +for path in PROXY_ROUTERS: + if type(path) is str: + try: + import_string(path) + except ImportError: + raise ImproperlyConfigured(f"Invalid path in PROXY_ROUTERS: {path}") + # # Database # -# Set the database engine -if 'ENGINE' not in DATABASE: - if METRICS_ENABLED: - DATABASE.update({'ENGINE': 'django_prometheus.db.backends.postgresql'}) - else: - DATABASE.update({'ENGINE': 'django.db.backends.postgresql'}) +# Verify that a default database has been configured +if 'default' not in DATABASES: + raise ImproperlyConfigured("No default database has been configured.") -# Define the DATABASES setting for Django -DATABASES = { - 'default': DATABASE, -} +# Set the database engine +if 'ENGINE' not in DATABASES['default']: + DATABASES['default'].update({ + 'ENGINE': 'django_prometheus.db.backends.postgresql' if METRICS_ENABLED else 'django.db.backends.postgresql' + }) # # Storage backend # +if STORAGE_BACKEND is not None: + if not STORAGES: + raise ImproperlyConfigured( + "STORAGE_BACKEND and STORAGES are both set, remove the deprecated STORAGE_BACKEND setting." + ) + else: + warnings.warn( + "STORAGE_BACKEND is deprecated, use the new STORAGES setting instead." + ) + +if STORAGE_CONFIG is not None: + warnings.warn( + "STORAGE_CONFIG is deprecated, use the new STORAGES setting instead." + ) + # Default STORAGES for Django -STORAGES = { +DEFAULT_STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", }, + "scripts": { + "BACKEND": "extras.storage.ScriptFileSystemStorage", + }, } +STORAGES = DEFAULT_STORAGES | STORAGES +# TODO: This code is deprecated and needs to be removed in the future if STORAGE_BACKEND is not None: STORAGES['default']['BACKEND'] = STORAGE_BACKEND - # django-storages - if STORAGE_BACKEND.startswith('storages.'): - try: - import storages.utils # type: ignore - except ModuleNotFoundError as e: - if getattr(e, 'name') == 'storages': - raise ImproperlyConfigured( - f"STORAGE_BACKEND is set to {STORAGE_BACKEND} but django-storages is not present. It can be " - f"installed by running 'pip install django-storages'." - ) - raise e +# Monkey-patch django-storages to fetch settings from STORAGE_CONFIG +if STORAGE_CONFIG is not None: + def _setting(name, default=None): + if name in STORAGE_CONFIG: + return STORAGE_CONFIG[name] + return globals().get(name, default) + storages.utils.setting = _setting - # Monkey-patch django-storages to fetch settings from STORAGE_CONFIG - def _setting(name, default=None): - if name in STORAGE_CONFIG: - return STORAGE_CONFIG[name] - return globals().get(name, default) - storages.utils.setting = _setting - - # django-storage-swift - elif STORAGE_BACKEND == 'swift.storage.SwiftStorage': - try: - import swift.utils # noqa: F401 - except ModuleNotFoundError as e: - if getattr(e, 'name') == 'swift': - raise ImproperlyConfigured( - f"STORAGE_BACKEND is set to {STORAGE_BACKEND} but django-storage-swift is not present. " - "It can be installed by running 'pip install django-storage-swift'." - ) - raise e - - # Load all SWIFT_* settings from the user configuration - for param, value in STORAGE_CONFIG.items(): - if param.startswith('SWIFT_'): - globals()[param] = value - -if STORAGE_CONFIG and STORAGE_BACKEND is None: - warnings.warn( - "STORAGE_CONFIG has been set in configuration.py but STORAGE_BACKEND is not defined. STORAGE_CONFIG will be " - "ignored." - ) +# django-storage-swift +if STORAGE_BACKEND == 'swift.storage.SwiftStorage': + try: + import swift.utils # noqa: F401 + except ModuleNotFoundError as e: + if getattr(e, 'name') == 'swift': + raise ImproperlyConfigured( + f"STORAGE_BACKEND is set to {STORAGE_BACKEND} but django-storage-swift is not present. " + "It can be installed by running 'pip install django-storage-swift'." + ) + raise e + # Load all SWIFT_* settings from the user configuration + for param, value in STORAGE_CONFIG.items(): + if param.startswith('SWIFT_'): + globals()[param] = value +# TODO: End of deprecated code # # Redis @@ -577,6 +599,7 @@ if SENTRY_ENABLED: sample_rate=SENTRY_SAMPLE_RATE, traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE, send_default_pii=SENTRY_SEND_DEFAULT_PII, + # TODO: Support proxy routing http_proxy=HTTP_PROXIES.get('http') if HTTP_PROXIES else None, https_proxy=HTTP_PROXIES.get('https') if HTTP_PROXIES else None ) @@ -776,7 +799,7 @@ LOCALE_PATHS = ( STRAWBERRY_DJANGO = { "DEFAULT_PK_FIELD_NAME": "id", "TYPE_DESCRIPTION_FROM_MODEL_DOCSTRING": True, - "USE_DEPRECATED_FILTERS": True, + "PAGINATION_DEFAULT_LIMIT": 100, } # @@ -811,6 +834,15 @@ for plugin_name in PLUGINS: f"__init__.py file and point to the PluginConfig subclass." ) + # Validate version compatibility and user-provided configuration settings and assign defaults + if plugin_name not in PLUGINS_CONFIG: + PLUGINS_CONFIG[plugin_name] = {} + try: + plugin_config.validate(PLUGINS_CONFIG[plugin_name], RELEASE.version) + except IncompatiblePluginError as e: + warnings.warn(f'Unable to load plugin {plugin_name}: {e}') + continue + # Register the plugin as installed successfully registry['plugins']['installed'].append(plugin_name) @@ -843,11 +875,6 @@ for plugin_name in PLUGINS: sorted_apps = reversed(list(dict.fromkeys(reversed(INSTALLED_APPS)))) INSTALLED_APPS = list(sorted_apps) - # Validate user-provided configuration settings and assign defaults - if plugin_name not in PLUGINS_CONFIG: - PLUGINS_CONFIG[plugin_name] = {} - plugin_config.validate(PLUGINS_CONFIG[plugin_name], RELEASE.version) - # Add middleware plugin_middleware = plugin_config.middleware if plugin_middleware and type(plugin_middleware) in (list, tuple): @@ -869,6 +896,7 @@ for plugin_name in PLUGINS: else: raise ImproperlyConfigured(f"events_pipline in plugin: {plugin_name} must be a list or tuple") + # UNSUPPORTED FUNCTIONALITY: Import any local overrides. try: from .local_settings import * diff --git a/netbox/netbox/staging.py b/netbox/netbox/staging.py deleted file mode 100644 index e6b94640302..00000000000 --- a/netbox/netbox/staging.py +++ /dev/null @@ -1,148 +0,0 @@ -import logging - -from django.contrib.contenttypes.models import ContentType -from django.db import transaction -from django.db.models.signals import m2m_changed, pre_delete, post_save - -from extras.choices import ChangeActionChoices -from extras.models import StagedChange -from utilities.serialization import serialize_object - -logger = logging.getLogger('netbox.staging') - - -class checkout: - """ - Context manager for staging changes to NetBox objects. Staged changes are saved out-of-band - (as Change instances) for application at a later time, without modifying the production - database. - - branch = Branch.objects.create(name='my-branch') - with checkout(branch): - # All changes made herein will be rolled back and stored for later - - Note that invoking the context disabled transaction autocommit to facilitate manual rollbacks, - and restores its original value upon exit. - """ - def __init__(self, branch): - self.branch = branch - self.queue = {} - - def __enter__(self): - - # Disable autocommit to effect a new transaction - logger.debug(f"Entering transaction for {self.branch}") - self._autocommit = transaction.get_autocommit() - transaction.set_autocommit(False) - - # Apply any existing Changes assigned to this Branch - staged_changes = self.branch.staged_changes.all() - if change_count := staged_changes.count(): - logger.debug(f"Applying {change_count} pre-staged changes...") - for change in staged_changes: - change.apply() - else: - logger.debug("No pre-staged changes found") - - # Connect signal handlers - logger.debug("Connecting signal handlers") - post_save.connect(self.post_save_handler) - m2m_changed.connect(self.post_save_handler) - pre_delete.connect(self.pre_delete_handler) - - def __exit__(self, exc_type, exc_val, exc_tb): - - # Disconnect signal handlers - logger.debug("Disconnecting signal handlers") - post_save.disconnect(self.post_save_handler) - m2m_changed.disconnect(self.post_save_handler) - pre_delete.disconnect(self.pre_delete_handler) - - # Roll back the transaction to return the database to its original state - logger.debug("Rolling back database transaction") - transaction.rollback() - logger.debug(f"Restoring autocommit state ({self._autocommit})") - transaction.set_autocommit(self._autocommit) - - # Process queued changes - self.process_queue() - - # - # Queuing - # - - @staticmethod - def get_key_for_instance(instance): - return ContentType.objects.get_for_model(instance), instance.pk - - def process_queue(self): - """ - Create Change instances for all actions stored in the queue. - """ - if not self.queue: - logger.debug("No queued changes; aborting") - return - logger.debug(f"Processing {len(self.queue)} queued changes") - - # Iterate through the in-memory queue, creating Change instances - changes = [] - for key, change in self.queue.items(): - logger.debug(f' {key}: {change}') - object_type, pk = key - action, data = change - - changes.append(StagedChange( - branch=self.branch, - action=action, - object_type=object_type, - object_id=pk, - data=data - )) - - # Save all Change instances to the database - StagedChange.objects.bulk_create(changes) - - # - # Signal handlers - # - - def post_save_handler(self, sender, instance, **kwargs): - """ - Hooks to the post_save signal when a branch is active to queue create and update actions. - """ - key = self.get_key_for_instance(instance) - object_type = instance._meta.verbose_name - - # Creating a new object - if kwargs.get('created'): - logger.debug(f"[{self.branch}] Staging creation of {object_type} {instance} (PK: {instance.pk})") - data = serialize_object(instance, resolve_tags=False) - self.queue[key] = (ChangeActionChoices.ACTION_CREATE, data) - return - - # Ignore pre_* many-to-many actions - if 'action' in kwargs and kwargs['action'] not in ('post_add', 'post_remove', 'post_clear'): - return - - # Object has already been created/updated in the queue; update its queued representation - if key in self.queue: - logger.debug(f"[{self.branch}] Updating staged value for {object_type} {instance} (PK: {instance.pk})") - data = serialize_object(instance, resolve_tags=False) - self.queue[key] = (self.queue[key][0], data) - return - - # Modifying an existing object for the first time - logger.debug(f"[{self.branch}] Staging changes to {object_type} {instance} (PK: {instance.pk})") - data = serialize_object(instance, resolve_tags=False) - self.queue[key] = (ChangeActionChoices.ACTION_UPDATE, data) - - def pre_delete_handler(self, sender, instance, **kwargs): - """ - Hooks to the pre_delete signal when a branch is active to queue delete actions. - """ - key = self.get_key_for_instance(instance) - object_type = instance._meta.verbose_name - - # Delete an existing object - logger.debug(f"[{self.branch}] Staging deletion of {object_type} {instance} (PK: {instance.pk})") - self.queue[key] = (ChangeActionChoices.ACTION_DELETE, None) diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index cf6e1f133ef..f0e55176d17 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -35,6 +35,7 @@ __all__ = ( 'ContentTypesColumn', 'CustomFieldColumn', 'CustomLinkColumn', + 'DictColumn', 'DistanceColumn', 'DurationColumn', 'LinkedCountColumn', @@ -707,3 +708,14 @@ class DistanceColumn(TemplateColumn): def __init__(self, template_code=template_code, order_by='_abs_distance', **kwargs): super().__init__(template_code=template_code, order_by=order_by, **kwargs) + + +class DictColumn(tables.Column): + """ + Render a dictionary of data in a simple key: value format, one pair per line. + """ + def render(self, value): + output = '
'.join([ + f'{escape(k)}: {escape(v)}' for k, v in value.items() + ]) + return mark_safe(output) diff --git a/netbox/netbox/tests/dummy_plugin/template_content.py b/netbox/netbox/tests/dummy_plugin/template_content.py index e9a6b9da1ce..e962594d45d 100644 --- a/netbox/netbox/tests/dummy_plugin/template_content.py +++ b/netbox/netbox/tests/dummy_plugin/template_content.py @@ -3,6 +3,9 @@ from netbox.plugins.templates import PluginTemplateExtension class GlobalContent(PluginTemplateExtension): + def head(self): + return "" + def navbar(self): return "GLOBAL CONTENT - NAVBAR" diff --git a/netbox/netbox/tests/test_graphql.py b/netbox/netbox/tests/test_graphql.py index b04d42d2447..ca231526fa7 100644 --- a/netbox/netbox/tests/test_graphql.py +++ b/netbox/netbox/tests/test_graphql.py @@ -99,8 +99,8 @@ class GraphQLAPITestCase(APITestCase): # Test OR logic query = """{ location_list( filters: { - status: \"""" + LocationStatusChoices.STATUS_PLANNED + """\", - OR: {status: \"""" + LocationStatusChoices.STATUS_STAGING + """\"} + status: STATUS_PLANNED, + OR: {status: STATUS_STAGING} }) { id site {id} } diff --git a/netbox/netbox/tests/test_staging.py b/netbox/netbox/tests/test_staging.py deleted file mode 100644 index 0a73b298722..00000000000 --- a/netbox/netbox/tests/test_staging.py +++ /dev/null @@ -1,216 +0,0 @@ -from django.db.models.signals import post_save -from django.test import TransactionTestCase - -from circuits.models import Provider, Circuit, CircuitType -from extras.choices import ChangeActionChoices -from extras.models import Branch, StagedChange, Tag -from ipam.models import ASN, RIR -from netbox.search.backends import search_backend -from netbox.staging import checkout -from utilities.testing import create_tags - - -class StagingTestCase(TransactionTestCase): - - def setUp(self): - # Disconnect search backend to avoid issues with cached ObjectTypes being deleted - # from the database upon transaction rollback - post_save.disconnect(search_backend.caching_handler) - - create_tags('Alpha', 'Bravo', 'Charlie') - - rir = RIR.objects.create(name='RIR 1', slug='rir-1') - asns = ( - ASN(asn=65001, rir=rir), - ASN(asn=65002, rir=rir), - ASN(asn=65003, rir=rir), - ) - ASN.objects.bulk_create(asns) - - providers = ( - Provider(name='Provider A', slug='provider-a'), - Provider(name='Provider B', slug='provider-b'), - Provider(name='Provider C', slug='provider-c'), - ) - Provider.objects.bulk_create(providers) - - circuit_type = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1') - - Circuit.objects.bulk_create(( - Circuit(provider=providers[0], cid='Circuit A1', type=circuit_type), - Circuit(provider=providers[0], cid='Circuit A2', type=circuit_type), - Circuit(provider=providers[0], cid='Circuit A3', type=circuit_type), - Circuit(provider=providers[1], cid='Circuit B1', type=circuit_type), - Circuit(provider=providers[1], cid='Circuit B2', type=circuit_type), - Circuit(provider=providers[1], cid='Circuit B3', type=circuit_type), - Circuit(provider=providers[2], cid='Circuit C1', type=circuit_type), - Circuit(provider=providers[2], cid='Circuit C2', type=circuit_type), - Circuit(provider=providers[2], cid='Circuit C3', type=circuit_type), - )) - - def test_object_creation(self): - branch = Branch.objects.create(name='Branch 1') - tags = Tag.objects.all() - asns = ASN.objects.all() - - with checkout(branch): - provider = Provider.objects.create(name='Provider D', slug='provider-d') - provider.asns.set(asns) - circuit = Circuit.objects.create(provider=provider, cid='Circuit D1', type=CircuitType.objects.first()) - circuit.tags.set(tags) - - # Sanity-checking - self.assertEqual(Provider.objects.count(), 4) - self.assertListEqual(list(provider.asns.all()), list(asns)) - self.assertEqual(Circuit.objects.count(), 10) - self.assertListEqual(list(circuit.tags.all()), list(tags)) - - # Verify that changes have been rolled back after exiting the context - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Circuit.objects.count(), 9) - self.assertEqual(StagedChange.objects.count(), 5) - - # Verify that changes are replayed upon entering the context - with checkout(branch): - self.assertEqual(Provider.objects.count(), 4) - self.assertEqual(Circuit.objects.count(), 10) - provider = Provider.objects.get(name='Provider D') - self.assertListEqual(list(provider.asns.all()), list(asns)) - circuit = Circuit.objects.get(cid='Circuit D1') - self.assertListEqual(list(circuit.tags.all()), list(tags)) - - # Verify that changes are applied and deleted upon branch merge - branch.merge() - self.assertEqual(Provider.objects.count(), 4) - self.assertEqual(Circuit.objects.count(), 10) - provider = Provider.objects.get(name='Provider D') - self.assertListEqual(list(provider.asns.all()), list(asns)) - circuit = Circuit.objects.get(cid='Circuit D1') - self.assertListEqual(list(circuit.tags.all()), list(tags)) - self.assertEqual(StagedChange.objects.count(), 0) - - def test_object_modification(self): - branch = Branch.objects.create(name='Branch 1') - tags = Tag.objects.all() - asns = ASN.objects.all() - - with checkout(branch): - provider = Provider.objects.get(name='Provider A') - provider.name = 'Provider X' - provider.save() - provider.asns.set(asns) - circuit = Circuit.objects.get(cid='Circuit A1') - circuit.cid = 'Circuit X' - circuit.save() - circuit.tags.set(tags) - - # Sanity-checking - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Provider.objects.get(pk=provider.pk).name, 'Provider X') - self.assertListEqual(list(provider.asns.all()), list(asns)) - self.assertEqual(Circuit.objects.count(), 9) - self.assertEqual(Circuit.objects.get(pk=circuit.pk).cid, 'Circuit X') - self.assertListEqual(list(circuit.tags.all()), list(tags)) - - # Verify that changes have been rolled back after exiting the context - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Provider.objects.get(pk=provider.pk).name, 'Provider A') - provider = Provider.objects.get(pk=provider.pk) - self.assertListEqual(list(provider.asns.all()), []) - self.assertEqual(Circuit.objects.count(), 9) - circuit = Circuit.objects.get(pk=circuit.pk) - self.assertEqual(circuit.cid, 'Circuit A1') - self.assertListEqual(list(circuit.tags.all()), []) - self.assertEqual(StagedChange.objects.count(), 5) - - # Verify that changes are replayed upon entering the context - with checkout(branch): - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Provider.objects.get(pk=provider.pk).name, 'Provider X') - provider = Provider.objects.get(pk=provider.pk) - self.assertListEqual(list(provider.asns.all()), list(asns)) - self.assertEqual(Circuit.objects.count(), 9) - circuit = Circuit.objects.get(pk=circuit.pk) - self.assertEqual(circuit.cid, 'Circuit X') - self.assertListEqual(list(circuit.tags.all()), list(tags)) - - # Verify that changes are applied and deleted upon branch merge - branch.merge() - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Provider.objects.get(pk=provider.pk).name, 'Provider X') - provider = Provider.objects.get(pk=provider.pk) - self.assertListEqual(list(provider.asns.all()), list(asns)) - self.assertEqual(Circuit.objects.count(), 9) - circuit = Circuit.objects.get(pk=circuit.pk) - self.assertEqual(circuit.cid, 'Circuit X') - self.assertListEqual(list(circuit.tags.all()), list(tags)) - self.assertEqual(StagedChange.objects.count(), 0) - - def test_object_deletion(self): - branch = Branch.objects.create(name='Branch 1') - - with checkout(branch): - provider = Provider.objects.get(name='Provider A') - provider.circuits.all().delete() - provider.delete() - - # Sanity-checking - self.assertEqual(Provider.objects.count(), 2) - self.assertEqual(Circuit.objects.count(), 6) - - # Verify that changes have been rolled back after exiting the context - self.assertEqual(Provider.objects.count(), 3) - self.assertEqual(Circuit.objects.count(), 9) - self.assertEqual(StagedChange.objects.count(), 4) - - # Verify that changes are replayed upon entering the context - with checkout(branch): - self.assertEqual(Provider.objects.count(), 2) - self.assertEqual(Circuit.objects.count(), 6) - - # Verify that changes are applied and deleted upon branch merge - branch.merge() - self.assertEqual(Provider.objects.count(), 2) - self.assertEqual(Circuit.objects.count(), 6) - self.assertEqual(StagedChange.objects.count(), 0) - - def test_exit_enter_context(self): - branch = Branch.objects.create(name='Branch 1') - - with checkout(branch): - - # Create a new object - provider = Provider.objects.create(name='Provider D', slug='provider-d') - provider.save() - - # Check that a create Change was recorded - self.assertEqual(StagedChange.objects.count(), 1) - change = StagedChange.objects.first() - self.assertEqual(change.action, ChangeActionChoices.ACTION_CREATE) - self.assertEqual(change.data['name'], provider.name) - - with checkout(branch): - - # Update the staged object - provider = Provider.objects.get(name='Provider D') - provider.comments = 'New comments' - provider.save() - - # Check that a second Change object has been created for the object - self.assertEqual(StagedChange.objects.count(), 2) - change = StagedChange.objects.last() - self.assertEqual(change.action, ChangeActionChoices.ACTION_UPDATE) - self.assertEqual(change.data['name'], provider.name) - self.assertEqual(change.data['comments'], provider.comments) - - with checkout(branch): - - # Delete the staged object - provider = Provider.objects.get(name='Provider D') - provider.delete() - - # Check that a third Change has recorded the object's deletion - self.assertEqual(StagedChange.objects.count(), 3) - change = StagedChange.objects.last() - self.assertEqual(change.action, ChangeActionChoices.ACTION_DELETE) - self.assertIsNone(change.data) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 88857ad54e2..447e2a6c536 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -107,7 +107,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin): request: The current request """ try: - return template.render_to_response(self.queryset) + return template.render_to_response(queryset=self.queryset) except Exception as e: messages.error( request, diff --git a/netbox/netbox/views/generic/feature_views.py b/netbox/netbox/views/generic/feature_views.py index 1e17d5354ef..63bbc86a514 100644 --- a/netbox/netbox/views/generic/feature_views.py +++ b/netbox/netbox/views/generic/feature_views.py @@ -12,13 +12,19 @@ from core.tables import JobTable, ObjectChangeTable from extras.forms import JournalEntryForm from extras.models import JournalEntry from extras.tables import JournalEntryTable +from tenancy.models import ContactAssignment +from tenancy.tables import ContactAssignmentTable +from tenancy.filtersets import ContactAssignmentFilterSet +from tenancy.forms import ContactAssignmentFilterForm from utilities.permissions import get_permission_for_model from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab from .base import BaseMultiObjectView +from .object_views import ObjectChildrenView __all__ = ( 'BulkSyncDataView', 'ObjectChangeLogView', + 'ObjectContactsView', 'ObjectJobsView', 'ObjectJournalView', 'ObjectSyncDataView', @@ -244,3 +250,25 @@ class BulkSyncDataView(GetReturnURLMixin, BaseMultiObjectView): )) return redirect(self.get_return_url(request)) + + +class ObjectContactsView(ObjectChildrenView): + child_model = ContactAssignment + table = ContactAssignmentTable + filterset = ContactAssignmentFilterSet + filterset_form = ContactAssignmentFilterForm + template_name = 'tenancy/object_contacts.html' + tab = ViewTab( + label=_('Contacts'), + badge=lambda obj: obj.get_contacts().count(), + permission='tenancy.view_contactassignment', + weight=5000 + ) + + def dispatch(self, request, *args, **kwargs): + model = kwargs.pop('model') + self.queryset = model.objects.all() + return super().dispatch(request, *args, **kwargs) + + def get_children(self, request, parent): + return parent.get_contacts().restrict(request.user, 'view').order_by('priority', 'contact', 'role') diff --git a/netbox/project-static/dist/netbox.css b/netbox/project-static/dist/netbox.css index 2cb549a0d20..5dbcf97cf07 100644 --- a/netbox/project-static/dist/netbox.css +++ b/netbox/project-static/dist/netbox.css @@ -1 +1 @@ -@charset "UTF-8";:root,[data-bs-theme=light]{--tblr-black: #000000;--tblr-white: #ffffff;--tblr-gray: #49566c;--tblr-gray-dark: #182433;--tblr-gray-100: #eef3f6;--tblr-gray-200: #dce1e7;--tblr-gray-300: #b8c4d4;--tblr-gray-400: #8a97ab;--tblr-gray-500: #6c7a91;--tblr-gray-600: #49566c;--tblr-gray-700: #3a4859;--tblr-gray-800: #182433;--tblr-gray-900: #040a11;--tblr-primary: #00857D;--tblr-secondary: #6c7a91;--tblr-success: #2fb344;--tblr-info: #4299e1;--tblr-warning: #f76707;--tblr-danger: #d63939;--tblr-light: #f6f8fb;--tblr-dark: #182433;--tblr-muted: #6c7a91;--tblr-blue: #066fd1;--tblr-azure: #4299e1;--tblr-indigo: #4263eb;--tblr-purple: #ae3ec9;--tblr-pink: #d6336c;--tblr-red: #d63939;--tblr-orange: #f76707;--tblr-yellow: #f59f00;--tblr-lime: #74b816;--tblr-green: #2fb344;--tblr-teal: #0ca678;--tblr-cyan: #17a2b8;--tblr-x: #000000;--tblr-facebook: #1877f2;--tblr-twitter: #1da1f2;--tblr-linkedin: #0a66c2;--tblr-google: #dc4e41;--tblr-youtube: #ff0000;--tblr-vimeo: #1ab7ea;--tblr-dribbble: #ea4c89;--tblr-github: #181717;--tblr-instagram: #e4405f;--tblr-pinterest: #bd081c;--tblr-vk: #6383a8;--tblr-rss: #ffa500;--tblr-flickr: #0063dc;--tblr-bitbucket: #0052cc;--tblr-tabler: #066fd1;--tblr-primary-rgb: 0, 133, 125;--tblr-secondary-rgb: 108, 122, 145;--tblr-success-rgb: 47, 179, 68;--tblr-info-rgb: 66, 153, 225;--tblr-warning-rgb: 247, 103, 7;--tblr-danger-rgb: 214, 57, 57;--tblr-light-rgb: 246, 248, 251;--tblr-dark-rgb: 24, 36, 51;--tblr-muted-rgb: 108, 122, 145;--tblr-blue-rgb: 6, 111, 209;--tblr-azure-rgb: 66, 153, 225;--tblr-indigo-rgb: 66, 99, 235;--tblr-purple-rgb: 174, 62, 201;--tblr-pink-rgb: 214, 51, 108;--tblr-red-rgb: 214, 57, 57;--tblr-orange-rgb: 247, 103, 7;--tblr-yellow-rgb: 245, 159, 0;--tblr-lime-rgb: 116, 184, 22;--tblr-green-rgb: 47, 179, 68;--tblr-teal-rgb: 12, 166, 120;--tblr-cyan-rgb: 23, 162, 184;--tblr-x-rgb: 0, 0, 0;--tblr-facebook-rgb: 24, 119, 242;--tblr-twitter-rgb: 29, 161, 242;--tblr-linkedin-rgb: 10, 102, 194;--tblr-google-rgb: 220, 78, 65;--tblr-youtube-rgb: 255, 0, 0;--tblr-vimeo-rgb: 26, 183, 234;--tblr-dribbble-rgb: 234, 76, 137;--tblr-github-rgb: 24, 23, 23;--tblr-instagram-rgb: 228, 64, 95;--tblr-pinterest-rgb: 189, 8, 28;--tblr-vk-rgb: 99, 131, 168;--tblr-rss-rgb: 255, 165, 0;--tblr-flickr-rgb: 0, 99, 220;--tblr-bitbucket-rgb: 0, 82, 204;--tblr-tabler-rgb: 6, 111, 209;--tblr-primary-text-emphasis: #003532;--tblr-secondary-text-emphasis: #2b313a;--tblr-success-text-emphasis: #13481b;--tblr-info-text-emphasis: #1a3d5a;--tblr-warning-text-emphasis: #632903;--tblr-danger-text-emphasis: #561717;--tblr-light-text-emphasis: #3a4859;--tblr-dark-text-emphasis: #3a4859;--tblr-primary-bg-subtle: #cce7e5;--tblr-secondary-bg-subtle: #e2e4e9;--tblr-success-bg-subtle: #d5f0da;--tblr-info-bg-subtle: #d9ebf9;--tblr-warning-bg-subtle: #fde1cd;--tblr-danger-bg-subtle: #f7d7d7;--tblr-light-bg-subtle: #f7f9fb;--tblr-dark-bg-subtle: #8a97ab;--tblr-primary-border-subtle: #99cecb;--tblr-secondary-border-subtle: #c4cad3;--tblr-success-border-subtle: #ace1b4;--tblr-info-border-subtle: #b3d6f3;--tblr-warning-border-subtle: #fcc29c;--tblr-danger-border-subtle: #efb0b0;--tblr-light-border-subtle: #dce1e7;--tblr-dark-border-subtle: #6c7a91;--tblr-white-rgb: 255, 255, 255;--tblr-black-rgb: 0, 0, 0;--tblr-font-sans-serif: "Inter", system-ui, sans-serif;--tblr-font-monospace: Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;--tblr-gradient: linear-gradient(180deg, rgba(255, 255, 255, .15), rgba(255, 255, 255, 0));--tblr-body-font-family: var(--tblr-font-sans-serif);--tblr-body-font-size: .875rem;--tblr-body-font-weight: 400;--tblr-body-line-height: 1.4285714286;--tblr-body-color: #182433;--tblr-body-color-rgb: 24, 36, 51;--tblr-body-bg: #f6f8fb;--tblr-body-bg-rgb: 246, 248, 251;--tblr-emphasis-color: #3a4859;--tblr-emphasis-color-rgb: 58, 72, 89;--tblr-secondary-color: rgba(24, 36, 51, .75);--tblr-secondary-color-rgb: 24, 36, 51;--tblr-secondary-bg: #dce1e7;--tblr-secondary-bg-rgb: 220, 225, 231;--tblr-tertiary-color: rgba(24, 36, 51, .5);--tblr-tertiary-color-rgb: 24, 36, 51;--tblr-tertiary-bg: #eef3f6;--tblr-tertiary-bg-rgb: 238, 243, 246;--tblr-heading-color: inherit;--tblr-link-color: #00857D;--tblr-link-color-rgb: 0, 133, 125;--tblr-link-decoration: none;--tblr-link-hover-color: #006a64;--tblr-link-hover-color-rgb: 0, 106, 100;--tblr-link-hover-decoration: underline;--tblr-code-color: var(--tblr-gray-600);--tblr-highlight-color: #182433;--tblr-highlight-bg: #fdeccc;--tblr-border-width: 1px;--tblr-border-style: solid;--tblr-border-color: #dce1e7;--tblr-border-color-translucent: rgba(4, 32, 69, .1);--tblr-border-radius: 4px;--tblr-border-radius-sm: 2px;--tblr-border-radius-lg: 8px;--tblr-border-radius-xl: 1rem;--tblr-border-radius-xxl: 2rem;--tblr-border-radius-2xl: var(--tblr-border-radius-xxl);--tblr-border-radius-pill: 100rem;--tblr-box-shadow: rgba(var(--tblr-body-color-rgb), .04) 0 2px 4px 0;--tblr-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--tblr-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--tblr-box-shadow-inset: 0 0 transparent;--tblr-focus-ring-width: .25rem;--tblr-focus-ring-opacity: .25;--tblr-focus-ring-color: rgba(var(--tblr-primary-rgb), .25);--tblr-form-valid-color: #2fb344;--tblr-form-valid-border-color: #2fb344;--tblr-form-invalid-color: #d63939;--tblr-form-invalid-border-color: #d63939}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{color-scheme:dark;--tblr-body-color: #dce1e7;--tblr-body-color-rgb: 220, 225, 231;--tblr-body-bg: #040a11;--tblr-body-bg-rgb: 4, 10, 17;--tblr-emphasis-color: #ffffff;--tblr-emphasis-color-rgb: 255, 255, 255;--tblr-secondary-color: rgba(220, 225, 231, .75);--tblr-secondary-color-rgb: 220, 225, 231;--tblr-secondary-bg: #182433;--tblr-secondary-bg-rgb: 24, 36, 51;--tblr-tertiary-color: rgba(220, 225, 231, .5);--tblr-tertiary-color-rgb: 220, 225, 231;--tblr-tertiary-bg: #0e1722;--tblr-tertiary-bg-rgb: 14, 23, 34;--tblr-primary-text-emphasis: #66b6b1;--tblr-secondary-text-emphasis: #a7afbd;--tblr-success-text-emphasis: #82d18f;--tblr-info-text-emphasis: #8ec2ed;--tblr-warning-text-emphasis: #faa46a;--tblr-danger-text-emphasis: #e68888;--tblr-light-text-emphasis: #eef3f6;--tblr-dark-text-emphasis: #b8c4d4;--tblr-primary-bg-subtle: #001b19;--tblr-secondary-bg-subtle: #16181d;--tblr-success-bg-subtle: #09240e;--tblr-info-bg-subtle: #0d1f2d;--tblr-warning-bg-subtle: #311501;--tblr-danger-bg-subtle: #2b0b0b;--tblr-light-bg-subtle: #182433;--tblr-dark-bg-subtle: #0c121a;--tblr-primary-border-subtle: #00504b;--tblr-secondary-border-subtle: #414957;--tblr-success-border-subtle: #1c6b29;--tblr-info-border-subtle: #285c87;--tblr-warning-border-subtle: #943e04;--tblr-danger-border-subtle: #802222;--tblr-light-border-subtle: #3a4859;--tblr-dark-border-subtle: #182433;--tblr-heading-color: inherit;--tblr-link-color: #66b6b1;--tblr-link-hover-color: #85c5c1;--tblr-link-color-rgb: 102, 182, 177;--tblr-link-hover-color-rgb: 133, 197, 193;--tblr-code-color: var(--tblr-gray-300);--tblr-highlight-color: #dce1e7;--tblr-highlight-bg: #624000;--tblr-border-color: #25384f;--tblr-border-color-translucent: rgba(72, 110, 149, .14);--tblr-form-valid-color: #82d18f;--tblr-form-valid-border-color: #82d18f;--tblr-form-invalid-color: #e68888;--tblr-form-invalid-border-color: #e68888}*,*:before,*:after{box-sizing:border-box}@media (prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--tblr-body-font-family);font-size:var(--tblr-body-font-size);font-weight:var(--tblr-body-font-weight);line-height:var(--tblr-body-line-height);color:var(--tblr-body-color);text-align:var(--tblr-body-text-align);background-color:var(--tblr-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr,.hr{margin:2rem 0;color:inherit;border:0;border-top:var(--tblr-border-width) solid;opacity:.16}h6,.h6,h5,.h5,h4,.h4,h3,.field-group h2,.field-group .h2,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:var(--tblr-spacer);font-weight:var(--tblr-font-weight-bold);line-height:1.2;color:var(--tblr-heading-color)}h1,.h1{font-size:1.5rem}h2,.h2{font-size:1.25rem}h3,.field-group h2,.field-group .h2,.h3{font-size:1rem}h4,.h4{font-size:.875rem}h5,.h5{font-size:.75rem}h6,.h6{font-size:.625rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;cursor:help;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:600}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:85.714285%}mark,.mark{padding:.1875em;color:var(--tblr-highlight-color);background-color:var(--tblr-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-opacity, 1));text-decoration:none}a:hover{--tblr-link-color-rgb: var(--tblr-link-hover-color-rgb);text-decoration:underline}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--tblr-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:85.714285%;color:var(--tblr-light)}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:85.714285%;color:var(--tblr-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.25rem .5rem;font-size:var(--tblr-font-size-h5);color:var(--tblr-text-secondary-dark);background-color:var(--tblr-code-bg);border-radius:2px}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--tblr-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}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]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:.875rem;font-weight:var(--tblr-font-weight-normal)}.display-1{font-size:5rem;font-weight:300;line-height:1.2}.display-2{font-size:4.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}.display-5{font-size:3rem;font-weight:300;line-height:1.2}.display-6{font-size:2rem;font-weight:300;line-height:1.2}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:85.714285%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:.875rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:85.714285%;color:#49566c}.blockquote-footer:before{content:"\2014\a0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--tblr-body-bg);border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-sm);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:85.714285%;color:var(--tblr-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width: 576px){.container-sm,.container{max-width:540px}}@media (min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media (min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media (min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media (min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--tblr-breakpoint-xs: 0;--tblr-breakpoint-sm: 576px;--tblr-breakpoint-md: 768px;--tblr-breakpoint-lg: 992px;--tblr-breakpoint-xl: 1200px;--tblr-breakpoint-xxl: 1400px}.row{--tblr-gutter-x: var(--tblr-page-padding);--tblr-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--tblr-gutter-y));margin-right:calc(-.5 * var(--tblr-gutter-x));margin-left:calc(-.5 * var(--tblr-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-top:var(--tblr-gutter-y)}.grid{display:grid;grid-template-rows:repeat(var(--tblr-rows, 1),1fr);grid-template-columns:repeat(var(--tblr-columns, 12),1fr);gap:var(--tblr-gap, var(--tblr-page-padding))}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media (min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media (min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media (min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media (min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media (min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-0,.gy-0{--tblr-gutter-y: 0}.g-1,.gx-1{--tblr-gutter-x: .25rem}.g-1,.gy-1{--tblr-gutter-y: .25rem}.g-2,.gx-2{--tblr-gutter-x: .5rem}.g-2,.gy-2{--tblr-gutter-y: .5rem}.g-3,.gx-3{--tblr-gutter-x: 1rem}.g-3,.gy-3{--tblr-gutter-y: 1rem}.g-4,.gx-4{--tblr-gutter-x: 1.5rem}.g-4,.gy-4{--tblr-gutter-y: 1.5rem}.g-5,.gx-5{--tblr-gutter-x: 2rem}.g-5,.gy-5{--tblr-gutter-y: 2rem}.g-6,.gx-6{--tblr-gutter-x: 3rem}.g-6,.gy-6{--tblr-gutter-y: 3rem}.g-7,.gx-7{--tblr-gutter-x: 5rem}.g-7,.gy-7{--tblr-gutter-y: 5rem}.g-8,.gx-8{--tblr-gutter-x: 8rem}.g-8,.gy-8{--tblr-gutter-y: 8rem}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-sm-0,.gy-sm-0{--tblr-gutter-y: 0}.g-sm-1,.gx-sm-1{--tblr-gutter-x: .25rem}.g-sm-1,.gy-sm-1{--tblr-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--tblr-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--tblr-gutter-y: .5rem}.g-sm-3,.gx-sm-3{--tblr-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--tblr-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--tblr-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--tblr-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--tblr-gutter-x: 2rem}.g-sm-5,.gy-sm-5{--tblr-gutter-y: 2rem}.g-sm-6,.gx-sm-6{--tblr-gutter-x: 3rem}.g-sm-6,.gy-sm-6{--tblr-gutter-y: 3rem}.g-sm-7,.gx-sm-7{--tblr-gutter-x: 5rem}.g-sm-7,.gy-sm-7{--tblr-gutter-y: 5rem}.g-sm-8,.gx-sm-8{--tblr-gutter-x: 8rem}.g-sm-8,.gy-sm-8{--tblr-gutter-y: 8rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-md-0,.gy-md-0{--tblr-gutter-y: 0}.g-md-1,.gx-md-1{--tblr-gutter-x: .25rem}.g-md-1,.gy-md-1{--tblr-gutter-y: .25rem}.g-md-2,.gx-md-2{--tblr-gutter-x: .5rem}.g-md-2,.gy-md-2{--tblr-gutter-y: .5rem}.g-md-3,.gx-md-3{--tblr-gutter-x: 1rem}.g-md-3,.gy-md-3{--tblr-gutter-y: 1rem}.g-md-4,.gx-md-4{--tblr-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--tblr-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--tblr-gutter-x: 2rem}.g-md-5,.gy-md-5{--tblr-gutter-y: 2rem}.g-md-6,.gx-md-6{--tblr-gutter-x: 3rem}.g-md-6,.gy-md-6{--tblr-gutter-y: 3rem}.g-md-7,.gx-md-7{--tblr-gutter-x: 5rem}.g-md-7,.gy-md-7{--tblr-gutter-y: 5rem}.g-md-8,.gx-md-8{--tblr-gutter-x: 8rem}.g-md-8,.gy-md-8{--tblr-gutter-y: 8rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-lg-0,.gy-lg-0{--tblr-gutter-y: 0}.g-lg-1,.gx-lg-1{--tblr-gutter-x: .25rem}.g-lg-1,.gy-lg-1{--tblr-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--tblr-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--tblr-gutter-y: .5rem}.g-lg-3,.gx-lg-3{--tblr-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--tblr-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--tblr-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--tblr-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--tblr-gutter-x: 2rem}.g-lg-5,.gy-lg-5{--tblr-gutter-y: 2rem}.g-lg-6,.gx-lg-6{--tblr-gutter-x: 3rem}.g-lg-6,.gy-lg-6{--tblr-gutter-y: 3rem}.g-lg-7,.gx-lg-7{--tblr-gutter-x: 5rem}.g-lg-7,.gy-lg-7{--tblr-gutter-y: 5rem}.g-lg-8,.gx-lg-8{--tblr-gutter-x: 8rem}.g-lg-8,.gy-lg-8{--tblr-gutter-y: 8rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-xl-0,.gy-xl-0{--tblr-gutter-y: 0}.g-xl-1,.gx-xl-1{--tblr-gutter-x: .25rem}.g-xl-1,.gy-xl-1{--tblr-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--tblr-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--tblr-gutter-y: .5rem}.g-xl-3,.gx-xl-3{--tblr-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--tblr-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--tblr-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--tblr-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--tblr-gutter-x: 2rem}.g-xl-5,.gy-xl-5{--tblr-gutter-y: 2rem}.g-xl-6,.gx-xl-6{--tblr-gutter-x: 3rem}.g-xl-6,.gy-xl-6{--tblr-gutter-y: 3rem}.g-xl-7,.gx-xl-7{--tblr-gutter-x: 5rem}.g-xl-7,.gy-xl-7{--tblr-gutter-y: 5rem}.g-xl-8,.gx-xl-8{--tblr-gutter-x: 8rem}.g-xl-8,.gy-xl-8{--tblr-gutter-y: 8rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--tblr-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--tblr-gutter-x: .25rem}.g-xxl-1,.gy-xxl-1{--tblr-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--tblr-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--tblr-gutter-y: .5rem}.g-xxl-3,.gx-xxl-3{--tblr-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--tblr-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--tblr-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--tblr-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--tblr-gutter-x: 2rem}.g-xxl-5,.gy-xxl-5{--tblr-gutter-y: 2rem}.g-xxl-6,.gx-xxl-6{--tblr-gutter-x: 3rem}.g-xxl-6,.gy-xxl-6{--tblr-gutter-y: 3rem}.g-xxl-7,.gx-xxl-7{--tblr-gutter-x: 5rem}.g-xxl-7,.gy-xxl-7{--tblr-gutter-y: 5rem}.g-xxl-8,.gx-xxl-8{--tblr-gutter-x: 8rem}.g-xxl-8,.gy-xxl-8{--tblr-gutter-y: 8rem}}.table,.markdown>table{--tblr-table-color-type: initial;--tblr-table-bg-type: initial;--tblr-table-color-state: initial;--tblr-table-bg-state: initial;--tblr-table-color: inherit;--tblr-table-bg: transparent;--tblr-table-border-color: var(--tblr-border-color-translucent);--tblr-table-accent-bg: transparent;--tblr-table-striped-color: inherit;--tblr-table-striped-bg: var(--tblr-bg-surface-tertiary);--tblr-table-active-color: inherit;--tblr-table-active-bg: rgba(var(--tblr-emphasis-color-rgb), .1);--tblr-table-hover-color: inherit;--tblr-table-hover-bg: rgba(var(--tblr-emphasis-color-rgb), .075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--tblr-table-border-color)}.table>:not(caption)>*>*,.markdown>table>:not(caption)>*>*{padding:.5rem;color:var(--tblr-table-color-state, var(--tblr-table-color-type, var(--tblr-table-color)));background-color:var(--tblr-table-bg);border-bottom-width:var(--tblr-border-width);box-shadow:inset 0 0 0 9999px var(--tblr-table-bg-state, var(--tblr-table-bg-type, var(--tblr-table-accent-bg)))}.table>tbody,.markdown>table>tbody{vertical-align:inherit}.table>thead,.markdown>table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--tblr-border-width) * 2) solid var(--tblr-border-color-translucent)}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*,.markdown>table>:not(caption)>*{border-width:var(--tblr-border-width) 0}.table-bordered>:not(caption)>*>*,.markdown>table>:not(caption)>*>*{border-width:0 var(--tblr-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(2n)>*{--tblr-table-color-type: var(--tblr-table-striped-color);--tblr-table-bg-type: var(--tblr-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--tblr-table-color-type: var(--tblr-table-striped-color);--tblr-table-bg-type: var(--tblr-table-striped-bg)}.table-active{--tblr-table-color-state: var(--tblr-table-active-color);--tblr-table-bg-state: var(--tblr-table-active-bg)}.table-hover>tbody>tr:hover>*{--tblr-table-color-state: var(--tblr-table-hover-color);--tblr-table-bg-state: var(--tblr-table-hover-bg)}.table-primary{--tblr-table-color: #182433;--tblr-table-bg: #cce7e5;--tblr-table-border-color: #a8c0c1;--tblr-table-striped-bg: #c3dddc;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #bad4d3;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #bfd8d8;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-secondary{--tblr-table-color: #182433;--tblr-table-bg: #e2e4e9;--tblr-table-border-color: #babec5;--tblr-table-striped-bg: #d8dae0;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #ced1d7;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #d3d6db;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-success{--tblr-table-color: #182433;--tblr-table-bg: #d5f0da;--tblr-table-border-color: #afc7b9;--tblr-table-striped-bg: #cce6d2;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #c2dcc9;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #c7e1cd;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-info{--tblr-table-color: #182433;--tblr-table-bg: #d9ebf9;--tblr-table-border-color: #b2c3d1;--tblr-table-striped-bg: #cfe1ef;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #c6d7e5;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #cbdcea;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-warning{--tblr-table-color: #182433;--tblr-table-bg: #fde1cd;--tblr-table-border-color: #cfbbae;--tblr-table-striped-bg: #f2d8c5;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e6cebe;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #ecd3c1;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-danger{--tblr-table-color: #182433;--tblr-table-bg: #f7d7d7;--tblr-table-border-color: #cab3b6;--tblr-table-striped-bg: #eccecf;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e1c5c7;--tblr-table-active-color: #f6f8fb;--tblr-table-hover-bg: #e6cacb;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-light{--tblr-table-color: #182433;--tblr-table-bg: #f6f8fb;--tblr-table-border-color: #caced3;--tblr-table-striped-bg: #ebedf1;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e0e3e7;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #e5e8ec;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-dark{--tblr-table-color: #f6f8fb;--tblr-table-bg: #182433;--tblr-table-border-color: #444e5b;--tblr-table-striped-bg: #232f3d;--tblr-table-striped-color: #f6f8fb;--tblr-table-active-bg: #2e3947;--tblr-table-active-color: #f6f8fb;--tblr-table-hover-bg: #293442;--tblr-table-hover-color: #f6f8fb;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem;font-size:.875rem;font-weight:var(--tblr-font-weight-medium)}.col-form-label{padding-top:calc(.5625rem + var(--tblr-border-width));padding-bottom:calc(.5625rem + var(--tblr-border-width));margin-bottom:0;font-size:inherit;font-weight:var(--tblr-font-weight-medium);line-height:1.4285714286}.col-form-label-lg{padding-top:calc(.5rem + var(--tblr-border-width));padding-bottom:calc(.5rem + var(--tblr-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.125rem + var(--tblr-border-width));padding-bottom:calc(.125rem + var(--tblr-border-width));font-size:.75rem}.form-text{margin-top:.25rem;font-size:85.714285%;color:var(--tblr-secondary-color)}.form-control{display:block;width:100%;padding:.5625rem .75rem;font-family:var(--tblr-font-sans-serif);font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-body-color);appearance:none;background-color:var(--tblr-bg-forms);background-clip:padding-box;border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--tblr-body-color);background-color:var(--tblr-bg-forms);border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.4285714286em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:#8a97ab;opacity:1}.form-control:disabled{background-color:var(--tblr-bg-surface-secondary);opacity:1}.form-control::file-selector-button{padding:.5625rem .75rem;margin:-.5625rem -.75rem;margin-inline-end:.75rem;color:var(--tblr-body-color);background-color:var(--tblr-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--tblr-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--tblr-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.5625rem 0;margin-bottom:0;line-height:1.4285714286;color:var(--tblr-body-color);background-color:transparent;border:solid transparent;border-width:var(--tblr-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.4285714286em + .25rem + calc(var(--tblr-border-width) * 2));padding:.125rem .25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.form-control-sm::file-selector-button{padding:.125rem .25rem;margin:-.125rem -.25rem;margin-inline-end:.25rem}.form-control-lg{min-height:calc(1.4285714286em + 1rem + calc(var(--tblr-border-width) * 2));padding:.5rem .75rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}.form-control-lg::file-selector-button{padding:.5rem .75rem;margin:-.5rem -.75rem;margin-inline-end:.75rem}textarea.form-control{min-height:calc(1.4285714286em + 1.125rem + calc(var(--tblr-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.4285714286em + .25rem + calc(var(--tblr-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.4285714286em + 1rem + calc(var(--tblr-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.4285714286em + 1.125rem + calc(var(--tblr-border-width) * 2));padding:.5625rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--tblr-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--tblr-border-radius)}.form-control-color.form-control-sm{height:calc(1.4285714286em + .25rem + calc(var(--tblr-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.4285714286em + 1rem + calc(var(--tblr-border-width) * 2))}.form-select{--tblr-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.5625rem 2.25rem .5625rem .75rem;font-family:var(--tblr-font-sans-serif);font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-body-color);appearance:none;background-color:var(--tblr-bg-forms);background-image:var(--tblr-form-select-bg-img),var(--tblr-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--tblr-bg-surface-secondary)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--tblr-body-color)}.form-select-sm{padding-top:.125rem;padding-bottom:.125rem;padding-left:.25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:.75rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}[data-bs-theme=dark] .form-select,body[data-bs-theme=dark] [data-bs-theme=light] .form-select{--tblr-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dce1e7' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.25rem;padding-left:2rem;margin-bottom:.75rem}.form-check .form-check-input{float:left;margin-left:-2rem}.form-check-reverse{padding-right:2rem;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-2rem;margin-left:0}.form-check-input{--tblr-form-check-bg: var(--tblr-bg-forms);flex-shrink:0;width:1.25rem;height:1.25rem;margin-top:.0892857143rem;vertical-align:top;appearance:none;background-color:var(--tblr-form-check-bg);background-image:var(--tblr-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:var(--tblr-border-radius)}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#80c2be;outline:0;box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-check-input:checked{background-color:var(--tblr-primary);border-color:var(--tblr-border-color-translucent)}.form-check-input:checked[type=checkbox]{--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:var(--tblr-primary);border-color:var(--tblr-primary);--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.7}.form-switch{padding-left:2.5rem}.form-switch .form-check-input{--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23dce1e7'/%3e%3c/svg%3e");width:2rem;margin-left:-2.5rem;background-image:var(--tblr-form-switch-bg);background-position:left center;border-radius:2rem;transition:background-position .15s ease-in-out}.form-switch .form-check-input:focus{--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2380c2be'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5rem;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5rem;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.4}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.25rem;padding:0;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #f6f8fb,0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #f6f8fb,0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.375rem;appearance:none;background-color:var(--tblr-primary);border:2px var(--tblr-border-style) #ffffff;border-radius:1rem;box-shadow:0 .1rem .25rem #0000001a;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b3dad8}.form-range::-webkit-slider-runnable-track{width:100%;height:.25rem;color:transparent;cursor:pointer;background-color:var(--tblr-border-color);border-color:transparent;border-radius:1rem;box-shadow:var(--tblr-box-shadow-inset)}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;background-color:var(--tblr-primary);border:2px var(--tblr-border-style) #ffffff;border-radius:1rem;box-shadow:0 .1rem .25rem #0000001a;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b3dad8}.form-range::-moz-range-track{width:100%;height:.25rem;color:transparent;cursor:pointer;background-color:var(--tblr-border-color);border-color:transparent;border-radius:1rem;box-shadow:var(--tblr-box-shadow-inset)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--tblr-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--tblr-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--tblr-border-width) * 2));min-height:calc(3.5rem + calc(var(--tblr-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--tblr-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--tblr-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:focus~label:after,.form-floating>.form-control:not(:placeholder-shown)~label:after,.form-floating>.form-control-plaintext~label:after,.form-floating>.form-select~label:after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:var(--tblr-bg-forms);border-radius:var(--tblr-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--tblr-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--tblr-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#49566c}.form-floating>:disabled~label:after,.form-floating>.form-control:disabled~label:after{background-color:var(--tblr-bg-surface-secondary)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.5625rem .75rem;font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-gray-500);text-align:center;white-space:nowrap;background-color:var(--tblr-bg-surface-secondary);border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem .75rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.125rem .25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.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):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{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:calc(var(--tblr-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:85.714285%;color:var(--tblr-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:var(--tblr-spacer-2) var(--tblr-spacer-2);margin-top:.1rem;font-size:.765625rem;color:#fff;background-color:var(--tblr-success);border-radius:var(--tblr-border-radius)}.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:var(--tblr-form-valid-border-color);padding-right:calc(1.4285714286em + 1.125rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.3571428572em + .28125rem) center;background-size:calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--tblr-form-valid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.4285714286em + 1.125rem);background-position:top calc(.3571428572em + .28125rem) right calc(.3571428572em + .28125rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--tblr-form-valid-border-color)}.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"]{--tblr-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--tblr-form-valid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.4285714286em + 1.125rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--tblr-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--tblr-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--tblr-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:85.714285%;color:var(--tblr-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:var(--tblr-spacer-2) var(--tblr-spacer-2);margin-top:.1rem;font-size:.765625rem;color:#fff;background-color:var(--tblr-danger);border-radius:var(--tblr-border-radius)}.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:var(--tblr-form-invalid-border-color);padding-right:calc(1.4285714286em + 1.125rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.3571428572em + .28125rem) center;background-size:calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--tblr-form-invalid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.4285714286em + 1.125rem);background-position:top calc(.3571428572em + .28125rem) right calc(.3571428572em + .28125rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--tblr-form-invalid-border-color)}.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"]{--tblr-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--tblr-form-invalid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.4285714286em + 1.125rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--tblr-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--tblr-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--tblr-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--tblr-btn-padding-x: .5rem;--tblr-btn-padding-y: .25rem;--tblr-btn-font-family: var(--tblr-font-sans-serif);--tblr-btn-font-size: .875rem;--tblr-btn-font-weight: var(--tblr-font-weight-medium);--tblr-btn-line-height: 1.4285714286;--tblr-btn-color: var(--tblr-body-color);--tblr-btn-bg: transparent;--tblr-btn-border-width: var(--tblr-border-width);--tblr-btn-border-color: transparent;--tblr-btn-border-radius: var(--tblr-border-radius);--tblr-btn-hover-border-color: transparent;--tblr-btn-box-shadow: var(--tblr-box-shadow-input);--tblr-btn-disabled-opacity: .4;--tblr-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--tblr-btn-padding-y) var(--tblr-btn-padding-x);font-family:var(--tblr-btn-font-family);font-size:var(--tblr-btn-font-size);font-weight:var(--tblr-btn-font-weight);line-height:var(--tblr-btn-line-height);color:var(--tblr-btn-color);text-align:center;vertical-align:middle;cursor:pointer;user-select:none;border:var(--tblr-btn-border-width) solid var(--tblr-btn-border-color);border-radius:var(--tblr-btn-border-radius);background-color:var(--tblr-btn-bg);box-shadow:var(--tblr-btn-box-shadow);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--tblr-btn-hover-color);text-decoration:none;background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--tblr-btn-color);background-color:var(--tblr-btn-bg);border-color:var(--tblr-btn-border-color)}.btn:focus-visible{color:var(--tblr-btn-hover-color);background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color);outline:0;box-shadow:var(--tblr-btn-box-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--tblr-btn-hover-border-color);outline:0;box-shadow:var(--tblr-btn-box-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--tblr-btn-active-color);background-color:var(--tblr-btn-active-bg);border-color:var(--tblr-btn-active-border-color);box-shadow:var(--tblr-btn-active-shadow)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--tblr-btn-active-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--tblr-btn-active-shadow),var(--tblr-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--tblr-btn-disabled-color);pointer-events:none;background-color:var(--tblr-btn-disabled-bg);border-color:var(--tblr-btn-disabled-border-color);opacity:var(--tblr-btn-disabled-opacity);box-shadow:none}.btn-link{--tblr-btn-font-weight: 400;--tblr-btn-color: var(--tblr-link-color);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-link-hover-color);--tblr-btn-hover-border-color: transparent;--tblr-btn-active-color: var(--tblr-link-hover-color);--tblr-btn-active-border-color: transparent;--tblr-btn-disabled-color: #49566c;--tblr-btn-disabled-border-color: transparent;--tblr-btn-box-shadow: 0 0 0 #000;--tblr-btn-focus-shadow-rgb: 37, 150, 144;text-decoration:none}.btn-link:hover,.btn-link:focus-visible{text-decoration:underline}.btn-link:focus-visible{color:var(--tblr-btn-color)}.btn-link:hover{color:var(--tblr-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--tblr-btn-padding-y: .5rem;--tblr-btn-padding-x: .75rem;--tblr-btn-font-size: 1.25rem;--tblr-btn-border-radius: var(--tblr-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--tblr-btn-padding-y: .125rem;--tblr-btn-padding-x: .25rem;--tblr-btn-font-size: .75rem;--tblr-btn-border-radius: var(--tblr-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-45deg)}.dropdown-menu{--tblr-dropdown-zindex: 1000;--tblr-dropdown-min-width: 11rem;--tblr-dropdown-padding-x: 0;--tblr-dropdown-padding-y: .25rem;--tblr-dropdown-spacer: 1px;--tblr-dropdown-font-size: .875rem;--tblr-dropdown-color: var(--tblr-body-color);--tblr-dropdown-bg: var(--tblr-bg-surface);--tblr-dropdown-border-color: var(--tblr-border-color-translucent);--tblr-dropdown-border-radius: var(--tblr-border-radius);--tblr-dropdown-border-width: var(--tblr-border-width);--tblr-dropdown-inner-border-radius: calc(var(--tblr-border-radius) - var(--tblr-border-width));--tblr-dropdown-divider-bg: var(--tblr-border-color-translucent);--tblr-dropdown-divider-margin-y: var(--tblr-spacer-2);--tblr-dropdown-box-shadow: var(--tblr-box-shadow-dropdown);--tblr-dropdown-link-color: inherit;--tblr-dropdown-link-hover-color: inherit;--tblr-dropdown-link-hover-bg: rgba(var(--tblr-secondary-rgb), .08);--tblr-dropdown-link-active-color: var(--tblr-primary);--tblr-dropdown-link-active-bg: var(--tblr-active-bg);--tblr-dropdown-link-disabled-color: var(--tblr-tertiary-color);--tblr-dropdown-item-padding-x: .75rem;--tblr-dropdown-item-padding-y: .5rem;--tblr-dropdown-header-color: #49566c;--tblr-dropdown-header-padding-x: .75rem;--tblr-dropdown-header-padding-y: .25rem;position:absolute;z-index:var(--tblr-dropdown-zindex);display:none;min-width:var(--tblr-dropdown-min-width);padding:var(--tblr-dropdown-padding-y) var(--tblr-dropdown-padding-x);margin:0;font-size:var(--tblr-dropdown-font-size);color:var(--tblr-dropdown-color);text-align:left;list-style:none;background-color:var(--tblr-dropdown-bg);background-clip:padding-box;border:var(--tblr-dropdown-border-width) solid var(--tblr-dropdown-border-color);border-radius:var(--tblr-dropdown-border-radius);box-shadow:var(--tblr-dropdown-box-shadow)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--tblr-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 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:var(--tblr-dropdown-spacer)}.dropup .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(135deg)}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--tblr-dropdown-spacer)}.dropend .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-135deg)}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--tblr-dropdown-spacer)}.dropstart .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(45deg)}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--tblr-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--tblr-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--tblr-dropdown-item-padding-y) var(--tblr-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--tblr-dropdown-link-color);text-align:inherit;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--tblr-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--tblr-dropdown-link-hover-color);text-decoration:none;background-color:var(--tblr-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--tblr-dropdown-link-active-color);text-decoration:none;background-color:var(--tblr-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--tblr-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--tblr-dropdown-header-padding-y) var(--tblr-dropdown-header-padding-x);margin-bottom:0;font-size:.765625rem;color:var(--tblr-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--tblr-dropdown-item-padding-y) var(--tblr-dropdown-item-padding-x);color:var(--tblr-dropdown-link-color)}.dropdown-menu-dark{--tblr-dropdown-color: #b8c4d4;--tblr-dropdown-bg: #182433;--tblr-dropdown-border-color: var(--tblr-border-color-translucent);--tblr-dropdown-box-shadow: ;--tblr-dropdown-link-color: #b8c4d4;--tblr-dropdown-link-hover-color: #ffffff;--tblr-dropdown-divider-bg: var(--tblr-border-color-translucent);--tblr-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--tblr-dropdown-link-active-color: var(--tblr-primary);--tblr-dropdown-link-active-bg: var(--tblr-active-bg);--tblr-dropdown-link-disabled-color: #6c7a91;--tblr-dropdown-header-color: #6c7a91}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--tblr-border-radius)}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--tblr-border-width) * -1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.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:.1875rem;padding-left:.1875rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.btn-group.show .dropdown-toggle{box-shadow:inset 0 3px 5px #00000020}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.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:calc(var(--tblr-border-width) * -1)}.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{--tblr-nav-link-padding-x: .75rem;--tblr-nav-link-padding-y: .5rem;--tblr-nav-link-font-weight: ;--tblr-nav-link-color: var(--tblr-gray-500);--tblr-nav-link-hover-color: var(--tblr-link-hover-color);--tblr-nav-link-disabled-color: var(--tblr-disabled-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--tblr-nav-link-padding-y) var(--tblr-nav-link-padding-x);font-size:var(--tblr-nav-link-font-size);font-weight:var(--tblr-nav-link-font-weight);color:var(--tblr-nav-link-color);background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}.nav-link:hover,.nav-link:focus{color:var(--tblr-nav-link-hover-color);text-decoration:none}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.nav-link.disabled,.nav-link:disabled{color:var(--tblr-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--tblr-nav-tabs-border-width: var(--tblr-border-width);--tblr-nav-tabs-border-color: var(--tblr-border-color);--tblr-nav-tabs-border-radius: var(--tblr-border-radius);--tblr-nav-tabs-link-hover-border-color: var(--tblr-border-color) var(--tblr-border-color) var(--tblr-border-color);--tblr-nav-tabs-link-active-color: var(--tblr-body-color);--tblr-nav-tabs-link-active-bg: var(--tblr-body-bg);--tblr-nav-tabs-link-active-border-color: var(--tblr-border-color) var(--tblr-border-color) var(--tblr-border-color);border-bottom:var(--tblr-nav-tabs-border-width) solid var(--tblr-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--tblr-nav-tabs-border-width));border:var(--tblr-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--tblr-nav-tabs-border-radius);border-top-right-radius:var(--tblr-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--tblr-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--tblr-nav-tabs-link-active-color);background-color:var(--tblr-nav-tabs-link-active-bg);border-color:var(--tblr-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--tblr-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--tblr-nav-pills-border-radius: var(--tblr-border-radius);--tblr-nav-pills-link-active-color: var(--tblr-primary);--tblr-nav-pills-link-active-bg: rgba(var(--tblr-secondary-rgb), .15)}.nav-pills .nav-link{border-radius:var(--tblr-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--tblr-nav-pills-link-active-color);background-color:var(--tblr-nav-pills-link-active-bg)}.nav-underline{--tblr-nav-underline-gap: 1rem;--tblr-nav-underline-border-width: .125rem;--tblr-nav-underline-link-active-color: var(--tblr-emphasis-color);gap:var(--tblr-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--tblr-nav-underline-border-width) solid transparent}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:600;color:var(--tblr-nav-underline-link-active-color);border-bottom-color:currentcolor}.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{--tblr-navbar-padding-x: 0;--tblr-navbar-padding-y: .25rem;--tblr-navbar-color: var(--tblr-body-color);--tblr-navbar-hover-color: rgba(var(--tblr-emphasis-color-rgb), .8);--tblr-navbar-disabled-color: var(--tblr-disabled-color);--tblr-navbar-active-color: var(--tblr-body-color) color;--tblr-navbar-brand-padding-y: .5rem;--tblr-navbar-brand-margin-end: 1rem;--tblr-navbar-brand-font-size: 1.25rem;--tblr-navbar-brand-color: var(--tblr-body-color);--tblr-navbar-brand-hover-color: var(--tblr-body-color) color;--tblr-navbar-nav-link-padding-x: .75rem;--tblr-navbar-toggler-padding-y: 0;--tblr-navbar-toggler-padding-x: 0;--tblr-navbar-toggler-font-size: 1rem;--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2824, 36, 51, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--tblr-navbar-toggler-border-color: rgba(var(--tblr-emphasis-color-rgb), .15);--tblr-navbar-toggler-border-radius: var(--tblr-border-radius);--tblr-navbar-toggler-focus-width: 0;--tblr-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--tblr-navbar-padding-y) var(--tblr-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--tblr-navbar-brand-padding-y);padding-bottom:var(--tblr-navbar-brand-padding-y);margin-right:var(--tblr-navbar-brand-margin-end);font-size:var(--tblr-navbar-brand-font-size);color:var(--tblr-navbar-brand-color);white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--tblr-navbar-brand-hover-color);text-decoration:none}.navbar-nav{--tblr-nav-link-padding-x: 0;--tblr-nav-link-padding-y: .5rem;--tblr-nav-link-font-weight: ;--tblr-nav-link-color: var(--tblr-navbar-color);--tblr-nav-link-hover-color: var(--tblr-navbar-hover-color);--tblr-nav-link-disabled-color: var(--tblr-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--tblr-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--tblr-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--tblr-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--tblr-navbar-toggler-padding-y) var(--tblr-navbar-toggler-padding-x);font-size:var(--tblr-navbar-toggler-font-size);line-height:1;color:var(--tblr-navbar-color);background-color:transparent;border:var(--tblr-border-width) solid var(--tblr-navbar-toggler-border-color);border-radius:var(--tblr-navbar-toggler-border-radius);transition:var(--tblr-navbar-toggler-transition)}@media (prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--tblr-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--tblr-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--tblr-scroll-height, 75vh);overflow-y:auto}@media (min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 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:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark],body[data-bs-theme=dark] .navbar[data-bs-theme=light]{--tblr-navbar-color: rgba(255, 255, 255, .7);--tblr-navbar-hover-color: rgba(255, 255, 255, .75);--tblr-navbar-disabled-color: var(--tblr-disabled-color);--tblr-navbar-active-color: #ffffff;--tblr-navbar-brand-color: #ffffff;--tblr-navbar-brand-hover-color: #ffffff;--tblr-navbar-toggler-border-color: rgba(255, 255, 255, .1);--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.7%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon,body[data-bs-theme=dark] [data-bs-theme=light] .navbar-toggler-icon{--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.7%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--tblr-card-spacer-y: 1rem;--tblr-card-spacer-x: 1.25rem;--tblr-card-title-spacer-y: 1.25rem;--tblr-card-title-color: ;--tblr-card-subtitle-color: ;--tblr-card-border-width: var(--tblr-border-width);--tblr-card-border-color: var(--tblr-border-color-translucent);--tblr-card-border-radius: var(--tblr-border-radius);--tblr-card-box-shadow: var(--tblr-shadow-card);--tblr-card-inner-border-radius: calc(var(--tblr-border-radius) - (var(--tblr-border-width)));--tblr-card-cap-padding-y: 1rem;--tblr-card-cap-padding-x: 1.25rem;--tblr-card-cap-bg: var(--tblr-bg-surface-tertiary);--tblr-card-cap-color: inherit;--tblr-card-height: ;--tblr-card-color: inherit;--tblr-card-bg: var(--tblr-bg-surface);--tblr-card-img-overlay-padding: 1rem;--tblr-card-group-margin: 1.5rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--tblr-card-height);color:var(--tblr-body-color);word-wrap:break-word;background-color:var(--tblr-card-bg);background-clip:border-box;border:var(--tblr-card-border-width) solid var(--tblr-card-border-color);border-radius:var(--tblr-card-border-radius);box-shadow:var(--tblr-card-box-shadow)}.card>hr,.card>.hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--tblr-card-inner-border-radius);border-top-right-radius:var(--tblr-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--tblr-card-inner-border-radius);border-bottom-left-radius:var(--tblr-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--tblr-card-spacer-y) var(--tblr-card-spacer-x);color:var(--tblr-card-color)}.card-title{margin-bottom:var(--tblr-card-title-spacer-y);color:var(--tblr-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--tblr-card-title-spacer-y));margin-bottom:0;color:var(--tblr-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:var(--tblr-card-spacer-x)}.card-header{padding:var(--tblr-card-cap-padding-y) var(--tblr-card-cap-padding-x);margin-bottom:0;color:var(--tblr-card-cap-color);background-color:var(--tblr-card-cap-bg);border-bottom:var(--tblr-card-border-width) solid var(--tblr-card-border-color)}.card-header:first-child{border-radius:var(--tblr-card-inner-border-radius) var(--tblr-card-inner-border-radius) 0 0}.card-footer{padding:var(--tblr-card-cap-padding-y) var(--tblr-card-cap-padding-x);color:var(--tblr-card-cap-color);background-color:var(--tblr-card-cap-bg);border-top:var(--tblr-card-border-width) solid var(--tblr-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--tblr-card-inner-border-radius) var(--tblr-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--tblr-card-cap-padding-x));margin-bottom:calc(-1 * var(--tblr-card-cap-padding-y));margin-left:calc(-.5 * var(--tblr-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--tblr-card-bg);border-bottom-color:var(--tblr-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--tblr-card-cap-padding-x));margin-left:calc(-.5 * var(--tblr-card-cap-padding-x))}.card-img-overlay{position:absolute;inset:0;padding:var(--tblr-card-img-overlay-padding);border-radius:var(--tblr-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--tblr-card-inner-border-radius);border-top-right-radius:var(--tblr-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--tblr-card-inner-border-radius);border-bottom-left-radius:var(--tblr-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--tblr-card-group-margin)}@media (min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--tblr-accordion-color: var(--tblr-body-color);--tblr-accordion-bg: transparent;--tblr-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--tblr-accordion-border-color: var(--tblr-border-color-translucent);--tblr-accordion-border-width: var(--tblr-border-width);--tblr-accordion-border-radius: var(--tblr-border-radius);--tblr-accordion-inner-border-radius: calc(var(--tblr-border-radius) - (var(--tblr-border-width)));--tblr-accordion-btn-padding-x: 1.25rem;--tblr-accordion-btn-padding-y: 1rem;--tblr-accordion-btn-color: var(--tblr-body-color);--tblr-accordion-btn-bg: transparent;--tblr-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23182433' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--tblr-accordion-btn-icon-width: 1rem;--tblr-accordion-btn-icon-transform: rotate(-180deg);--tblr-accordion-btn-icon-transition: transform .2s ease-in-out;--tblr-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23003532' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--tblr-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-accordion-body-padding-x: 1.25rem;--tblr-accordion-body-padding-y: 1rem;--tblr-accordion-active-color: inherit;--tblr-accordion-active-bg: transparent}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--tblr-accordion-btn-padding-y) var(--tblr-accordion-btn-padding-x);font-size:.875rem;color:var(--tblr-accordion-btn-color);text-align:left;background-color:var(--tblr-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--tblr-accordion-transition)}@media (prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--tblr-accordion-active-color);background-color:var(--tblr-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--tblr-accordion-border-width)) 0 var(--tblr-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--tblr-accordion-btn-active-icon);transform:var(--tblr-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--tblr-accordion-btn-icon-width);height:var(--tblr-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--tblr-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--tblr-accordion-btn-icon-width);transition:var(--tblr-accordion-btn-icon-transition)}@media (prefers-reduced-motion: reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--tblr-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--tblr-accordion-color);background-color:var(--tblr-accordion-bg);border:var(--tblr-accordion-border-width) solid var(--tblr-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--tblr-accordion-border-radius);border-top-right-radius:var(--tblr-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--tblr-accordion-inner-border-radius);border-top-right-radius:var(--tblr-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--tblr-accordion-border-radius);border-bottom-left-radius:var(--tblr-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--tblr-accordion-inner-border-radius);border-bottom-left-radius:var(--tblr-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--tblr-accordion-border-radius);border-bottom-left-radius:var(--tblr-accordion-border-radius)}.accordion-body{padding:var(--tblr-accordion-body-padding-y) var(--tblr-accordion-body-padding-x)}.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-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button:after{--tblr-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2366b6b1'%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");--tblr-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2366b6b1'%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")}.breadcrumb{--tblr-breadcrumb-padding-x: 0;--tblr-breadcrumb-padding-y: 0;--tblr-breadcrumb-margin-bottom: 1rem;--tblr-breadcrumb-bg: ;--tblr-breadcrumb-border-radius: ;--tblr-breadcrumb-divider-color: var(--tblr-gray-500);--tblr-breadcrumb-item-padding-x: .5rem;--tblr-breadcrumb-item-active-color: inherit;display:flex;flex-wrap:wrap;padding:var(--tblr-breadcrumb-padding-y) var(--tblr-breadcrumb-padding-x);margin-bottom:var(--tblr-breadcrumb-margin-bottom);font-size:var(--tblr-breadcrumb-font-size);list-style:none;background-color:var(--tblr-breadcrumb-bg);border-radius:var(--tblr-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--tblr-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--tblr-breadcrumb-item-padding-x);color:var(--tblr-breadcrumb-divider-color);content:var(--tblr-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--tblr-breadcrumb-item-active-color)}.pagination{--tblr-pagination-padding-x: .25rem;--tblr-pagination-padding-y: .25rem;--tblr-pagination-font-size: .875rem;--tblr-pagination-color: var(--tblr-gray-500);--tblr-pagination-bg: transparent;--tblr-pagination-border-width: 0;--tblr-pagination-border-color: var(--tblr-border-color);--tblr-pagination-border-radius: var(--tblr-border-radius);--tblr-pagination-hover-color: var(--tblr-link-hover-color);--tblr-pagination-hover-bg: var(--tblr-tertiary-bg);--tblr-pagination-hover-border-color: var(--tblr-border-color);--tblr-pagination-focus-color: var(--tblr-link-hover-color);--tblr-pagination-focus-bg: var(--tblr-secondary-bg);--tblr-pagination-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-pagination-active-color: #ffffff;--tblr-pagination-active-bg: var(--tblr-primary);--tblr-pagination-active-border-color: var(--tblr-primary);--tblr-pagination-disabled-color: var(--tblr-disabled-color);--tblr-pagination-disabled-bg: transparent;--tblr-pagination-disabled-border-color: var(--tblr-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--tblr-pagination-padding-y) var(--tblr-pagination-padding-x);font-size:var(--tblr-pagination-font-size);color:var(--tblr-pagination-color);background-color:var(--tblr-pagination-bg);border:var(--tblr-pagination-border-width) solid var(--tblr-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--tblr-pagination-hover-color);text-decoration:none;background-color:var(--tblr-pagination-hover-bg);border-color:var(--tblr-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--tblr-pagination-focus-color);background-color:var(--tblr-pagination-focus-bg);outline:0;box-shadow:var(--tblr-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--tblr-pagination-active-color);background-color:var(--tblr-pagination-active-bg);border-color:var(--tblr-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--tblr-pagination-disabled-color);pointer-events:none;background-color:var(--tblr-pagination-disabled-bg);border-color:var(--tblr-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:-0}.page-item:first-child .page-link{border-top-left-radius:var(--tblr-pagination-border-radius);border-bottom-left-radius:var(--tblr-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--tblr-pagination-border-radius);border-bottom-right-radius:var(--tblr-pagination-border-radius)}.pagination-lg{--tblr-pagination-padding-x: 1.5rem;--tblr-pagination-padding-y: .75rem;--tblr-pagination-font-size: 1.09375rem;--tblr-pagination-border-radius: var(--tblr-border-radius-lg)}.pagination-sm{--tblr-pagination-padding-x: .5rem;--tblr-pagination-padding-y: .25rem;--tblr-pagination-font-size: .765625rem;--tblr-pagination-border-radius: var(--tblr-border-radius-sm)}.badge{--tblr-badge-padding-x: .5em;--tblr-badge-padding-y: .25em;--tblr-badge-font-size: 85.714285%;--tblr-badge-font-weight: var(--tblr-font-weight-medium);--tblr-badge-color: var(--tblr-gray-500);--tblr-badge-border-radius: var(--tblr-border-radius);display:inline-block;padding:var(--tblr-badge-padding-y) var(--tblr-badge-padding-x);font-size:var(--tblr-badge-font-size);font-weight:var(--tblr-badge-font-weight);line-height:1;color:var(--tblr-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--tblr-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--tblr-alert-bg: transparent;--tblr-alert-padding-x: 1rem;--tblr-alert-padding-y: .75rem;--tblr-alert-margin-bottom: 1rem;--tblr-alert-color: inherit;--tblr-alert-border-color: transparent;--tblr-alert-border: var(--tblr-border-width) solid var(--tblr-alert-border-color);--tblr-alert-border-radius: var(--tblr-border-radius);--tblr-alert-link-color: inherit;position:relative;padding:var(--tblr-alert-padding-y) var(--tblr-alert-padding-x);margin-bottom:var(--tblr-alert-margin-bottom);color:var(--tblr-alert-color);background-color:var(--tblr-alert-bg);border:var(--tblr-alert-border);border-radius:var(--tblr-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:var(--tblr-font-weight-bold);color:var(--tblr-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:.9375rem 1rem}.alert-primary{--tblr-alert-color: var(--tblr-primary-text-emphasis);--tblr-alert-bg: var(--tblr-primary-bg-subtle);--tblr-alert-border-color: var(--tblr-primary-border-subtle);--tblr-alert-link-color: var(--tblr-primary-text-emphasis)}.alert-secondary{--tblr-alert-color: var(--tblr-secondary-text-emphasis);--tblr-alert-bg: var(--tblr-secondary-bg-subtle);--tblr-alert-border-color: var(--tblr-secondary-border-subtle);--tblr-alert-link-color: var(--tblr-secondary-text-emphasis)}.alert-success{--tblr-alert-color: var(--tblr-success-text-emphasis);--tblr-alert-bg: var(--tblr-success-bg-subtle);--tblr-alert-border-color: var(--tblr-success-border-subtle);--tblr-alert-link-color: var(--tblr-success-text-emphasis)}.alert-info{--tblr-alert-color: var(--tblr-info-text-emphasis);--tblr-alert-bg: var(--tblr-info-bg-subtle);--tblr-alert-border-color: var(--tblr-info-border-subtle);--tblr-alert-link-color: var(--tblr-info-text-emphasis)}.alert-warning{--tblr-alert-color: var(--tblr-warning-text-emphasis);--tblr-alert-bg: var(--tblr-warning-bg-subtle);--tblr-alert-border-color: var(--tblr-warning-border-subtle);--tblr-alert-link-color: var(--tblr-warning-text-emphasis)}.alert-danger{--tblr-alert-color: var(--tblr-danger-text-emphasis);--tblr-alert-bg: var(--tblr-danger-bg-subtle);--tblr-alert-border-color: var(--tblr-danger-border-subtle);--tblr-alert-link-color: var(--tblr-danger-text-emphasis)}.alert-light{--tblr-alert-color: var(--tblr-light-text-emphasis);--tblr-alert-bg: var(--tblr-light-bg-subtle);--tblr-alert-border-color: var(--tblr-light-border-subtle);--tblr-alert-link-color: var(--tblr-light-text-emphasis)}.alert-dark{--tblr-alert-color: var(--tblr-dark-text-emphasis);--tblr-alert-bg: var(--tblr-dark-bg-subtle);--tblr-alert-border-color: var(--tblr-dark-border-subtle);--tblr-alert-link-color: var(--tblr-dark-text-emphasis)}.alert-muted{--tblr-alert-color: var(--tblr-muted-text-emphasis);--tblr-alert-bg: var(--tblr-muted-bg-subtle);--tblr-alert-border-color: var(--tblr-muted-border-subtle);--tblr-alert-link-color: var(--tblr-muted-text-emphasis)}.alert-blue{--tblr-alert-color: var(--tblr-blue-text-emphasis);--tblr-alert-bg: var(--tblr-blue-bg-subtle);--tblr-alert-border-color: var(--tblr-blue-border-subtle);--tblr-alert-link-color: var(--tblr-blue-text-emphasis)}.alert-azure{--tblr-alert-color: var(--tblr-azure-text-emphasis);--tblr-alert-bg: var(--tblr-azure-bg-subtle);--tblr-alert-border-color: var(--tblr-azure-border-subtle);--tblr-alert-link-color: var(--tblr-azure-text-emphasis)}.alert-indigo{--tblr-alert-color: var(--tblr-indigo-text-emphasis);--tblr-alert-bg: var(--tblr-indigo-bg-subtle);--tblr-alert-border-color: var(--tblr-indigo-border-subtle);--tblr-alert-link-color: var(--tblr-indigo-text-emphasis)}.alert-purple{--tblr-alert-color: var(--tblr-purple-text-emphasis);--tblr-alert-bg: var(--tblr-purple-bg-subtle);--tblr-alert-border-color: var(--tblr-purple-border-subtle);--tblr-alert-link-color: var(--tblr-purple-text-emphasis)}.alert-pink{--tblr-alert-color: var(--tblr-pink-text-emphasis);--tblr-alert-bg: var(--tblr-pink-bg-subtle);--tblr-alert-border-color: var(--tblr-pink-border-subtle);--tblr-alert-link-color: var(--tblr-pink-text-emphasis)}.alert-red{--tblr-alert-color: var(--tblr-red-text-emphasis);--tblr-alert-bg: var(--tblr-red-bg-subtle);--tblr-alert-border-color: var(--tblr-red-border-subtle);--tblr-alert-link-color: var(--tblr-red-text-emphasis)}.alert-orange{--tblr-alert-color: var(--tblr-orange-text-emphasis);--tblr-alert-bg: var(--tblr-orange-bg-subtle);--tblr-alert-border-color: var(--tblr-orange-border-subtle);--tblr-alert-link-color: var(--tblr-orange-text-emphasis)}.alert-yellow{--tblr-alert-color: var(--tblr-yellow-text-emphasis);--tblr-alert-bg: var(--tblr-yellow-bg-subtle);--tblr-alert-border-color: var(--tblr-yellow-border-subtle);--tblr-alert-link-color: var(--tblr-yellow-text-emphasis)}.alert-lime{--tblr-alert-color: var(--tblr-lime-text-emphasis);--tblr-alert-bg: var(--tblr-lime-bg-subtle);--tblr-alert-border-color: var(--tblr-lime-border-subtle);--tblr-alert-link-color: var(--tblr-lime-text-emphasis)}.alert-green{--tblr-alert-color: var(--tblr-green-text-emphasis);--tblr-alert-bg: var(--tblr-green-bg-subtle);--tblr-alert-border-color: var(--tblr-green-border-subtle);--tblr-alert-link-color: var(--tblr-green-text-emphasis)}.alert-teal{--tblr-alert-color: var(--tblr-teal-text-emphasis);--tblr-alert-bg: var(--tblr-teal-bg-subtle);--tblr-alert-border-color: var(--tblr-teal-border-subtle);--tblr-alert-link-color: var(--tblr-teal-text-emphasis)}.alert-cyan{--tblr-alert-color: var(--tblr-cyan-text-emphasis);--tblr-alert-bg: var(--tblr-cyan-bg-subtle);--tblr-alert-border-color: var(--tblr-cyan-border-subtle);--tblr-alert-link-color: var(--tblr-cyan-text-emphasis)}.alert-x{--tblr-alert-color: var(--tblr-x-text-emphasis);--tblr-alert-bg: var(--tblr-x-bg-subtle);--tblr-alert-border-color: var(--tblr-x-border-subtle);--tblr-alert-link-color: var(--tblr-x-text-emphasis)}.alert-facebook{--tblr-alert-color: var(--tblr-facebook-text-emphasis);--tblr-alert-bg: var(--tblr-facebook-bg-subtle);--tblr-alert-border-color: var(--tblr-facebook-border-subtle);--tblr-alert-link-color: var(--tblr-facebook-text-emphasis)}.alert-twitter{--tblr-alert-color: var(--tblr-twitter-text-emphasis);--tblr-alert-bg: var(--tblr-twitter-bg-subtle);--tblr-alert-border-color: var(--tblr-twitter-border-subtle);--tblr-alert-link-color: var(--tblr-twitter-text-emphasis)}.alert-linkedin{--tblr-alert-color: var(--tblr-linkedin-text-emphasis);--tblr-alert-bg: var(--tblr-linkedin-bg-subtle);--tblr-alert-border-color: var(--tblr-linkedin-border-subtle);--tblr-alert-link-color: var(--tblr-linkedin-text-emphasis)}.alert-google{--tblr-alert-color: var(--tblr-google-text-emphasis);--tblr-alert-bg: var(--tblr-google-bg-subtle);--tblr-alert-border-color: var(--tblr-google-border-subtle);--tblr-alert-link-color: var(--tblr-google-text-emphasis)}.alert-youtube{--tblr-alert-color: var(--tblr-youtube-text-emphasis);--tblr-alert-bg: var(--tblr-youtube-bg-subtle);--tblr-alert-border-color: var(--tblr-youtube-border-subtle);--tblr-alert-link-color: var(--tblr-youtube-text-emphasis)}.alert-vimeo{--tblr-alert-color: var(--tblr-vimeo-text-emphasis);--tblr-alert-bg: var(--tblr-vimeo-bg-subtle);--tblr-alert-border-color: var(--tblr-vimeo-border-subtle);--tblr-alert-link-color: var(--tblr-vimeo-text-emphasis)}.alert-dribbble{--tblr-alert-color: var(--tblr-dribbble-text-emphasis);--tblr-alert-bg: var(--tblr-dribbble-bg-subtle);--tblr-alert-border-color: var(--tblr-dribbble-border-subtle);--tblr-alert-link-color: var(--tblr-dribbble-text-emphasis)}.alert-github{--tblr-alert-color: var(--tblr-github-text-emphasis);--tblr-alert-bg: var(--tblr-github-bg-subtle);--tblr-alert-border-color: var(--tblr-github-border-subtle);--tblr-alert-link-color: var(--tblr-github-text-emphasis)}.alert-instagram{--tblr-alert-color: var(--tblr-instagram-text-emphasis);--tblr-alert-bg: var(--tblr-instagram-bg-subtle);--tblr-alert-border-color: var(--tblr-instagram-border-subtle);--tblr-alert-link-color: var(--tblr-instagram-text-emphasis)}.alert-pinterest{--tblr-alert-color: var(--tblr-pinterest-text-emphasis);--tblr-alert-bg: var(--tblr-pinterest-bg-subtle);--tblr-alert-border-color: var(--tblr-pinterest-border-subtle);--tblr-alert-link-color: var(--tblr-pinterest-text-emphasis)}.alert-vk{--tblr-alert-color: var(--tblr-vk-text-emphasis);--tblr-alert-bg: var(--tblr-vk-bg-subtle);--tblr-alert-border-color: var(--tblr-vk-border-subtle);--tblr-alert-link-color: var(--tblr-vk-text-emphasis)}.alert-rss{--tblr-alert-color: var(--tblr-rss-text-emphasis);--tblr-alert-bg: var(--tblr-rss-bg-subtle);--tblr-alert-border-color: var(--tblr-rss-border-subtle);--tblr-alert-link-color: var(--tblr-rss-text-emphasis)}.alert-flickr{--tblr-alert-color: var(--tblr-flickr-text-emphasis);--tblr-alert-bg: var(--tblr-flickr-bg-subtle);--tblr-alert-border-color: var(--tblr-flickr-border-subtle);--tblr-alert-link-color: var(--tblr-flickr-text-emphasis)}.alert-bitbucket{--tblr-alert-color: var(--tblr-bitbucket-text-emphasis);--tblr-alert-bg: var(--tblr-bitbucket-bg-subtle);--tblr-alert-border-color: var(--tblr-bitbucket-border-subtle);--tblr-alert-link-color: var(--tblr-bitbucket-text-emphasis)}.alert-tabler{--tblr-alert-color: var(--tblr-tabler-text-emphasis);--tblr-alert-bg: var(--tblr-tabler-bg-subtle);--tblr-alert-border-color: var(--tblr-tabler-border-subtle);--tblr-alert-link-color: var(--tblr-tabler-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress,.progress-stacked{--tblr-progress-height: .5rem;--tblr-progress-font-size: .65625rem;--tblr-progress-bg: var(--tblr-border-color);--tblr-progress-border-radius: var(--tblr-border-radius);--tblr-progress-box-shadow: var(--tblr-box-shadow-inset);--tblr-progress-bar-color: #ffffff;--tblr-progress-bar-bg: var(--tblr-primary);--tblr-progress-bar-transition: width .6s ease;display:flex;height:var(--tblr-progress-height);overflow:hidden;font-size:var(--tblr-progress-font-size);background-color:var(--tblr-progress-bg);border-radius:var(--tblr-progress-border-radius);box-shadow:var(--tblr-progress-box-shadow)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--tblr-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--tblr-progress-bar-bg);transition:var(--tblr-progress-bar-transition)}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--tblr-progress-height) var(--tblr-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--tblr-list-group-color: var(--tblr-body-color);--tblr-list-group-bg: inherit;--tblr-list-group-border-color: var(--tblr-border-color);--tblr-list-group-border-width: var(--tblr-border-width);--tblr-list-group-border-radius: var(--tblr-border-radius);--tblr-list-group-item-padding-x: 1.25rem;--tblr-list-group-item-padding-y: 1rem;--tblr-list-group-action-color: inherit;--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: rgba(var(--tblr-secondary-rgb), .08);--tblr-list-group-action-active-color: var(--tblr-body-color);--tblr-list-group-action-active-bg: var(--tblr-secondary-bg);--tblr-list-group-disabled-color: var(--tblr-secondary-color);--tblr-list-group-disabled-bg: inherit;--tblr-list-group-active-color: inherit;--tblr-list-group-active-bg: var(--tblr-active-bg);--tblr-list-group-active-border-color: var(--tblr-border-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--tblr-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--tblr-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--tblr-list-group-action-hover-color);text-decoration:none;background-color:var(--tblr-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--tblr-list-group-action-active-color);background-color:var(--tblr-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--tblr-list-group-item-padding-y) var(--tblr-list-group-item-padding-x);color:var(--tblr-list-group-color);background-color:var(--tblr-list-group-bg);border:var(--tblr-list-group-border-width) solid var(--tblr-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--tblr-list-group-disabled-color);pointer-events:none;background-color:var(--tblr-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--tblr-list-group-active-color);background-color:var(--tblr-list-group-active-bg);border-color:var(--tblr-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--tblr-list-group-border-width));border-top-width:var(--tblr-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}@media (min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--tblr-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--tblr-list-group-color: var(--tblr-primary-text-emphasis);--tblr-list-group-bg: var(--tblr-primary-bg-subtle);--tblr-list-group-border-color: var(--tblr-primary-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-primary-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-primary-border-subtle);--tblr-list-group-active-color: var(--tblr-primary-bg-subtle);--tblr-list-group-active-bg: var(--tblr-primary-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-primary-text-emphasis)}.list-group-item-secondary{--tblr-list-group-color: var(--tblr-secondary-text-emphasis);--tblr-list-group-bg: var(--tblr-secondary-bg-subtle);--tblr-list-group-border-color: var(--tblr-secondary-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-secondary-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-secondary-border-subtle);--tblr-list-group-active-color: var(--tblr-secondary-bg-subtle);--tblr-list-group-active-bg: var(--tblr-secondary-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-secondary-text-emphasis)}.list-group-item-success{--tblr-list-group-color: var(--tblr-success-text-emphasis);--tblr-list-group-bg: var(--tblr-success-bg-subtle);--tblr-list-group-border-color: var(--tblr-success-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-success-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-success-border-subtle);--tblr-list-group-active-color: var(--tblr-success-bg-subtle);--tblr-list-group-active-bg: var(--tblr-success-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-success-text-emphasis)}.list-group-item-info{--tblr-list-group-color: var(--tblr-info-text-emphasis);--tblr-list-group-bg: var(--tblr-info-bg-subtle);--tblr-list-group-border-color: var(--tblr-info-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-info-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-info-border-subtle);--tblr-list-group-active-color: var(--tblr-info-bg-subtle);--tblr-list-group-active-bg: var(--tblr-info-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-info-text-emphasis)}.list-group-item-warning{--tblr-list-group-color: var(--tblr-warning-text-emphasis);--tblr-list-group-bg: var(--tblr-warning-bg-subtle);--tblr-list-group-border-color: var(--tblr-warning-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-warning-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-warning-border-subtle);--tblr-list-group-active-color: var(--tblr-warning-bg-subtle);--tblr-list-group-active-bg: var(--tblr-warning-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-warning-text-emphasis)}.list-group-item-danger{--tblr-list-group-color: var(--tblr-danger-text-emphasis);--tblr-list-group-bg: var(--tblr-danger-bg-subtle);--tblr-list-group-border-color: var(--tblr-danger-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-danger-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-danger-border-subtle);--tblr-list-group-active-color: var(--tblr-danger-bg-subtle);--tblr-list-group-active-bg: var(--tblr-danger-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-danger-text-emphasis)}.list-group-item-light{--tblr-list-group-color: var(--tblr-light-text-emphasis);--tblr-list-group-bg: var(--tblr-light-bg-subtle);--tblr-list-group-border-color: var(--tblr-light-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-light-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-light-border-subtle);--tblr-list-group-active-color: var(--tblr-light-bg-subtle);--tblr-list-group-active-bg: var(--tblr-light-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-light-text-emphasis)}.list-group-item-dark{--tblr-list-group-color: var(--tblr-dark-text-emphasis);--tblr-list-group-bg: var(--tblr-dark-bg-subtle);--tblr-list-group-border-color: var(--tblr-dark-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-dark-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-dark-border-subtle);--tblr-list-group-active-color: var(--tblr-dark-bg-subtle);--tblr-list-group-active-bg: var(--tblr-dark-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-dark-text-emphasis)}.list-group-item-muted{--tblr-list-group-color: var(--tblr-muted-text-emphasis);--tblr-list-group-bg: var(--tblr-muted-bg-subtle);--tblr-list-group-border-color: var(--tblr-muted-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-muted-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-muted-border-subtle);--tblr-list-group-active-color: var(--tblr-muted-bg-subtle);--tblr-list-group-active-bg: var(--tblr-muted-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-muted-text-emphasis)}.list-group-item-blue{--tblr-list-group-color: var(--tblr-blue-text-emphasis);--tblr-list-group-bg: var(--tblr-blue-bg-subtle);--tblr-list-group-border-color: var(--tblr-blue-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-blue-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-blue-border-subtle);--tblr-list-group-active-color: var(--tblr-blue-bg-subtle);--tblr-list-group-active-bg: var(--tblr-blue-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-blue-text-emphasis)}.list-group-item-azure{--tblr-list-group-color: var(--tblr-azure-text-emphasis);--tblr-list-group-bg: var(--tblr-azure-bg-subtle);--tblr-list-group-border-color: var(--tblr-azure-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-azure-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-azure-border-subtle);--tblr-list-group-active-color: var(--tblr-azure-bg-subtle);--tblr-list-group-active-bg: var(--tblr-azure-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-azure-text-emphasis)}.list-group-item-indigo{--tblr-list-group-color: var(--tblr-indigo-text-emphasis);--tblr-list-group-bg: var(--tblr-indigo-bg-subtle);--tblr-list-group-border-color: var(--tblr-indigo-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-indigo-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-indigo-border-subtle);--tblr-list-group-active-color: var(--tblr-indigo-bg-subtle);--tblr-list-group-active-bg: var(--tblr-indigo-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-indigo-text-emphasis)}.list-group-item-purple{--tblr-list-group-color: var(--tblr-purple-text-emphasis);--tblr-list-group-bg: var(--tblr-purple-bg-subtle);--tblr-list-group-border-color: var(--tblr-purple-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-purple-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-purple-border-subtle);--tblr-list-group-active-color: var(--tblr-purple-bg-subtle);--tblr-list-group-active-bg: var(--tblr-purple-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-purple-text-emphasis)}.list-group-item-pink{--tblr-list-group-color: var(--tblr-pink-text-emphasis);--tblr-list-group-bg: var(--tblr-pink-bg-subtle);--tblr-list-group-border-color: var(--tblr-pink-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-pink-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-pink-border-subtle);--tblr-list-group-active-color: var(--tblr-pink-bg-subtle);--tblr-list-group-active-bg: var(--tblr-pink-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-pink-text-emphasis)}.list-group-item-red{--tblr-list-group-color: var(--tblr-red-text-emphasis);--tblr-list-group-bg: var(--tblr-red-bg-subtle);--tblr-list-group-border-color: var(--tblr-red-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-red-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-red-border-subtle);--tblr-list-group-active-color: var(--tblr-red-bg-subtle);--tblr-list-group-active-bg: var(--tblr-red-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-red-text-emphasis)}.list-group-item-orange{--tblr-list-group-color: var(--tblr-orange-text-emphasis);--tblr-list-group-bg: var(--tblr-orange-bg-subtle);--tblr-list-group-border-color: var(--tblr-orange-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-orange-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-orange-border-subtle);--tblr-list-group-active-color: var(--tblr-orange-bg-subtle);--tblr-list-group-active-bg: var(--tblr-orange-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-orange-text-emphasis)}.list-group-item-yellow{--tblr-list-group-color: var(--tblr-yellow-text-emphasis);--tblr-list-group-bg: var(--tblr-yellow-bg-subtle);--tblr-list-group-border-color: var(--tblr-yellow-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-yellow-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-yellow-border-subtle);--tblr-list-group-active-color: var(--tblr-yellow-bg-subtle);--tblr-list-group-active-bg: var(--tblr-yellow-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-yellow-text-emphasis)}.list-group-item-lime{--tblr-list-group-color: var(--tblr-lime-text-emphasis);--tblr-list-group-bg: var(--tblr-lime-bg-subtle);--tblr-list-group-border-color: var(--tblr-lime-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-lime-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-lime-border-subtle);--tblr-list-group-active-color: var(--tblr-lime-bg-subtle);--tblr-list-group-active-bg: var(--tblr-lime-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-lime-text-emphasis)}.list-group-item-green{--tblr-list-group-color: var(--tblr-green-text-emphasis);--tblr-list-group-bg: var(--tblr-green-bg-subtle);--tblr-list-group-border-color: var(--tblr-green-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-green-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-green-border-subtle);--tblr-list-group-active-color: var(--tblr-green-bg-subtle);--tblr-list-group-active-bg: var(--tblr-green-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-green-text-emphasis)}.list-group-item-teal{--tblr-list-group-color: var(--tblr-teal-text-emphasis);--tblr-list-group-bg: var(--tblr-teal-bg-subtle);--tblr-list-group-border-color: var(--tblr-teal-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-teal-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-teal-border-subtle);--tblr-list-group-active-color: var(--tblr-teal-bg-subtle);--tblr-list-group-active-bg: var(--tblr-teal-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-teal-text-emphasis)}.list-group-item-cyan{--tblr-list-group-color: var(--tblr-cyan-text-emphasis);--tblr-list-group-bg: var(--tblr-cyan-bg-subtle);--tblr-list-group-border-color: var(--tblr-cyan-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-cyan-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-cyan-border-subtle);--tblr-list-group-active-color: var(--tblr-cyan-bg-subtle);--tblr-list-group-active-bg: var(--tblr-cyan-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-cyan-text-emphasis)}.list-group-item-x{--tblr-list-group-color: var(--tblr-x-text-emphasis);--tblr-list-group-bg: var(--tblr-x-bg-subtle);--tblr-list-group-border-color: var(--tblr-x-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-x-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-x-border-subtle);--tblr-list-group-active-color: var(--tblr-x-bg-subtle);--tblr-list-group-active-bg: var(--tblr-x-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-x-text-emphasis)}.list-group-item-facebook{--tblr-list-group-color: var(--tblr-facebook-text-emphasis);--tblr-list-group-bg: var(--tblr-facebook-bg-subtle);--tblr-list-group-border-color: var(--tblr-facebook-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-facebook-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-facebook-border-subtle);--tblr-list-group-active-color: var(--tblr-facebook-bg-subtle);--tblr-list-group-active-bg: var(--tblr-facebook-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-facebook-text-emphasis)}.list-group-item-twitter{--tblr-list-group-color: var(--tblr-twitter-text-emphasis);--tblr-list-group-bg: var(--tblr-twitter-bg-subtle);--tblr-list-group-border-color: var(--tblr-twitter-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-twitter-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-twitter-border-subtle);--tblr-list-group-active-color: var(--tblr-twitter-bg-subtle);--tblr-list-group-active-bg: var(--tblr-twitter-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-twitter-text-emphasis)}.list-group-item-linkedin{--tblr-list-group-color: var(--tblr-linkedin-text-emphasis);--tblr-list-group-bg: var(--tblr-linkedin-bg-subtle);--tblr-list-group-border-color: var(--tblr-linkedin-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-linkedin-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-linkedin-border-subtle);--tblr-list-group-active-color: var(--tblr-linkedin-bg-subtle);--tblr-list-group-active-bg: var(--tblr-linkedin-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-linkedin-text-emphasis)}.list-group-item-google{--tblr-list-group-color: var(--tblr-google-text-emphasis);--tblr-list-group-bg: var(--tblr-google-bg-subtle);--tblr-list-group-border-color: var(--tblr-google-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-google-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-google-border-subtle);--tblr-list-group-active-color: var(--tblr-google-bg-subtle);--tblr-list-group-active-bg: var(--tblr-google-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-google-text-emphasis)}.list-group-item-youtube{--tblr-list-group-color: var(--tblr-youtube-text-emphasis);--tblr-list-group-bg: var(--tblr-youtube-bg-subtle);--tblr-list-group-border-color: var(--tblr-youtube-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-youtube-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-youtube-border-subtle);--tblr-list-group-active-color: var(--tblr-youtube-bg-subtle);--tblr-list-group-active-bg: var(--tblr-youtube-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-youtube-text-emphasis)}.list-group-item-vimeo{--tblr-list-group-color: var(--tblr-vimeo-text-emphasis);--tblr-list-group-bg: var(--tblr-vimeo-bg-subtle);--tblr-list-group-border-color: var(--tblr-vimeo-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-vimeo-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-vimeo-border-subtle);--tblr-list-group-active-color: var(--tblr-vimeo-bg-subtle);--tblr-list-group-active-bg: var(--tblr-vimeo-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-vimeo-text-emphasis)}.list-group-item-dribbble{--tblr-list-group-color: var(--tblr-dribbble-text-emphasis);--tblr-list-group-bg: var(--tblr-dribbble-bg-subtle);--tblr-list-group-border-color: var(--tblr-dribbble-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-dribbble-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-dribbble-border-subtle);--tblr-list-group-active-color: var(--tblr-dribbble-bg-subtle);--tblr-list-group-active-bg: var(--tblr-dribbble-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-dribbble-text-emphasis)}.list-group-item-github{--tblr-list-group-color: var(--tblr-github-text-emphasis);--tblr-list-group-bg: var(--tblr-github-bg-subtle);--tblr-list-group-border-color: var(--tblr-github-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-github-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-github-border-subtle);--tblr-list-group-active-color: var(--tblr-github-bg-subtle);--tblr-list-group-active-bg: var(--tblr-github-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-github-text-emphasis)}.list-group-item-instagram{--tblr-list-group-color: var(--tblr-instagram-text-emphasis);--tblr-list-group-bg: var(--tblr-instagram-bg-subtle);--tblr-list-group-border-color: var(--tblr-instagram-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-instagram-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-instagram-border-subtle);--tblr-list-group-active-color: var(--tblr-instagram-bg-subtle);--tblr-list-group-active-bg: var(--tblr-instagram-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-instagram-text-emphasis)}.list-group-item-pinterest{--tblr-list-group-color: var(--tblr-pinterest-text-emphasis);--tblr-list-group-bg: var(--tblr-pinterest-bg-subtle);--tblr-list-group-border-color: var(--tblr-pinterest-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-pinterest-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-pinterest-border-subtle);--tblr-list-group-active-color: var(--tblr-pinterest-bg-subtle);--tblr-list-group-active-bg: var(--tblr-pinterest-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-pinterest-text-emphasis)}.list-group-item-vk{--tblr-list-group-color: var(--tblr-vk-text-emphasis);--tblr-list-group-bg: var(--tblr-vk-bg-subtle);--tblr-list-group-border-color: var(--tblr-vk-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-vk-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-vk-border-subtle);--tblr-list-group-active-color: var(--tblr-vk-bg-subtle);--tblr-list-group-active-bg: var(--tblr-vk-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-vk-text-emphasis)}.list-group-item-rss{--tblr-list-group-color: var(--tblr-rss-text-emphasis);--tblr-list-group-bg: var(--tblr-rss-bg-subtle);--tblr-list-group-border-color: var(--tblr-rss-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-rss-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-rss-border-subtle);--tblr-list-group-active-color: var(--tblr-rss-bg-subtle);--tblr-list-group-active-bg: var(--tblr-rss-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-rss-text-emphasis)}.list-group-item-flickr{--tblr-list-group-color: var(--tblr-flickr-text-emphasis);--tblr-list-group-bg: var(--tblr-flickr-bg-subtle);--tblr-list-group-border-color: var(--tblr-flickr-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-flickr-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-flickr-border-subtle);--tblr-list-group-active-color: var(--tblr-flickr-bg-subtle);--tblr-list-group-active-bg: var(--tblr-flickr-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-flickr-text-emphasis)}.list-group-item-bitbucket{--tblr-list-group-color: var(--tblr-bitbucket-text-emphasis);--tblr-list-group-bg: var(--tblr-bitbucket-bg-subtle);--tblr-list-group-border-color: var(--tblr-bitbucket-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-bitbucket-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-bitbucket-border-subtle);--tblr-list-group-active-color: var(--tblr-bitbucket-bg-subtle);--tblr-list-group-active-bg: var(--tblr-bitbucket-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-bitbucket-text-emphasis)}.list-group-item-tabler{--tblr-list-group-color: var(--tblr-tabler-text-emphasis);--tblr-list-group-bg: var(--tblr-tabler-bg-subtle);--tblr-list-group-border-color: var(--tblr-tabler-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-tabler-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-tabler-border-subtle);--tblr-list-group-active-color: var(--tblr-tabler-bg-subtle);--tblr-list-group-active-bg: var(--tblr-tabler-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-tabler-text-emphasis)}.btn-close{--tblr-btn-close-color: #182433;--tblr-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23182433'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--tblr-btn-close-opacity: .4;--tblr-btn-close-hover-opacity: .75;--tblr-btn-close-focus-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-btn-close-focus-opacity: 1;--tblr-btn-close-disabled-opacity: .25;--tblr-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em;color:var(--tblr-btn-close-color);background:transparent var(--tblr-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:4px;opacity:var(--tblr-btn-close-opacity)}.btn-close:hover{color:var(--tblr-btn-close-color);text-decoration:none;opacity:var(--tblr-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--tblr-btn-close-focus-shadow);opacity:var(--tblr-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;opacity:var(--tblr-btn-close-disabled-opacity)}.btn-close-white,[data-bs-theme=dark] .btn-close,body[data-bs-theme=dark] [data-bs-theme=light] .btn-close{filter:var(--tblr-btn-close-white-filter)}.toast{--tblr-toast-zindex: 1090;--tblr-toast-padding-x: .75rem;--tblr-toast-padding-y: .5rem;--tblr-toast-spacing: calc(var(--tblr-page-padding) * 2);--tblr-toast-max-width: 350px;--tblr-toast-font-size: .875rem;--tblr-toast-color: ;--tblr-toast-bg: rgba(var(--tblr-body-bg-rgb), .85);--tblr-toast-border-width: var(--tblr-border-width);--tblr-toast-border-color: var(--tblr-border-color);--tblr-toast-border-radius: var(--tblr-border-radius);--tblr-toast-box-shadow: var(--tblr-box-shadow);--tblr-toast-header-color: var(--tblr-gray-500);--tblr-toast-header-bg: rgba(var(--tblr-body-bg-rgb), .85);--tblr-toast-header-border-color: var(--tblr-border-color);width:var(--tblr-toast-max-width);max-width:100%;font-size:var(--tblr-toast-font-size);color:var(--tblr-toast-color);pointer-events:auto;background-color:var(--tblr-toast-bg);background-clip:padding-box;border:var(--tblr-toast-border-width) solid var(--tblr-toast-border-color);box-shadow:var(--tblr-toast-box-shadow);border-radius:var(--tblr-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--tblr-toast-zindex: 1090;position:absolute;z-index:var(--tblr-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--tblr-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--tblr-toast-padding-y) var(--tblr-toast-padding-x);color:var(--tblr-toast-header-color);background-color:var(--tblr-toast-header-bg);background-clip:padding-box;border-bottom:var(--tblr-toast-border-width) solid var(--tblr-toast-header-border-color);border-top-left-radius:calc(var(--tblr-toast-border-radius) - var(--tblr-toast-border-width));border-top-right-radius:calc(var(--tblr-toast-border-radius) - var(--tblr-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--tblr-toast-padding-x));margin-left:var(--tblr-toast-padding-x)}.toast-body{padding:var(--tblr-toast-padding-x);word-wrap:break-word}.modal{--tblr-modal-zindex: 1055;--tblr-modal-width: 540px;--tblr-modal-padding: 1.5rem;--tblr-modal-margin: .5rem;--tblr-modal-color: ;--tblr-modal-bg: var(--tblr-bg-surface);--tblr-modal-border-color: transparent;--tblr-modal-border-width: var(--tblr-border-width);--tblr-modal-border-radius: var(--tblr-border-radius-lg);--tblr-modal-box-shadow: var(--tblr-box-shadow-sm);--tblr-modal-inner-border-radius: calc(var(--tblr-modal-border-radius) - 1px);--tblr-modal-header-padding-x: 1.5rem;--tblr-modal-header-padding-y: 1.5rem;--tblr-modal-header-padding: 1.5rem;--tblr-modal-header-border-color: var(--tblr-border-color);--tblr-modal-header-border-width: var(--tblr-border-width);--tblr-modal-title-line-height: 1.4285714286;--tblr-modal-footer-gap: .75rem;--tblr-modal-footer-bg: var(--tblr-bg-surface-tertiary);--tblr-modal-footer-border-color: var(--tblr-border-color);--tblr-modal-footer-border-width: var(--tblr-border-width);position:fixed;top:0;left:0;z-index:var(--tblr-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--tblr-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translateY(-1rem)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--tblr-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--tblr-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--tblr-modal-color);pointer-events:auto;background-color:var(--tblr-modal-bg);background-clip:padding-box;border:var(--tblr-modal-border-width) solid var(--tblr-modal-border-color);border-radius:var(--tblr-modal-border-radius);box-shadow:var(--tblr-modal-box-shadow);outline:0}.modal-backdrop{--tblr-backdrop-zindex: 1050;--tblr-backdrop-bg: #182433;--tblr-backdrop-opacity: .24;position:fixed;top:0;left:0;z-index:var(--tblr-backdrop-zindex);width:100vw;height:100vh;background-color:var(--tblr-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--tblr-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--tblr-modal-header-padding);border-bottom:var(--tblr-modal-header-border-width) solid var(--tblr-modal-header-border-color);border-top-left-radius:var(--tblr-modal-inner-border-radius);border-top-right-radius:var(--tblr-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--tblr-modal-header-padding-y) * .5) calc(var(--tblr-modal-header-padding-x) * .5);margin:calc(-.5 * var(--tblr-modal-header-padding-y)) calc(-.5 * var(--tblr-modal-header-padding-x)) calc(-.5 * var(--tblr-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--tblr-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--tblr-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--tblr-modal-padding) - var(--tblr-modal-footer-gap) * .5);background-color:var(--tblr-modal-footer-bg);border-top:var(--tblr-modal-footer-border-width) solid var(--tblr-modal-footer-border-color);border-bottom-right-radius:var(--tblr-modal-inner-border-radius);border-bottom-left-radius:var(--tblr-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--tblr-modal-footer-gap) * .5)}@media (min-width: 576px){.modal{--tblr-modal-margin: 1.75rem;--tblr-modal-box-shadow: var(--tblr-box-shadow)}.modal-dialog{max-width:var(--tblr-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--tblr-modal-width: 380px}}@media (min-width: 992px){.modal-lg,.modal-xl{--tblr-modal-width: 720px}}@media (min-width: 1200px){.modal-xl{--tblr-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width: 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,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--tblr-tooltip-zindex: 1080;--tblr-tooltip-max-width: 200px;--tblr-tooltip-padding-x: var(--tblr-spacer-2);--tblr-tooltip-padding-y: var(--tblr-spacer-2);--tblr-tooltip-margin: ;--tblr-tooltip-font-size: .765625rem;--tblr-tooltip-color: var(--tblr-light);--tblr-tooltip-bg: var(--tblr-bg-surface-dark);--tblr-tooltip-border-radius: var(--tblr-border-radius);--tblr-tooltip-opacity: .9;--tblr-tooltip-arrow-width: .8rem;--tblr-tooltip-arrow-height: .4rem;z-index:var(--tblr-tooltip-zindex);display:block;margin:var(--tblr-tooltip-margin);font-family:var(--tblr-font-sans-serif);font-style:normal;font-weight:400;line-height:1.4285714286;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--tblr-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--tblr-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--tblr-tooltip-arrow-width);height:var(--tblr-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1 * var(--tblr-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before{top:-1px;border-width:var(--tblr-tooltip-arrow-height) calc(var(--tblr-tooltip-arrow-width) * .5) 0;border-top-color:var(--tblr-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1 * var(--tblr-tooltip-arrow-height));width:var(--tblr-tooltip-arrow-height);height:var(--tblr-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before{right:-1px;border-width:calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height) calc(var(--tblr-tooltip-arrow-width) * .5) 0;border-right-color:var(--tblr-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1 * var(--tblr-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height);border-bottom-color:var(--tblr-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1 * var(--tblr-tooltip-arrow-height));width:var(--tblr-tooltip-arrow-height);height:var(--tblr-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before{left:-1px;border-width:calc(var(--tblr-tooltip-arrow-width) * .5) 0 calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height);border-left-color:var(--tblr-tooltip-bg)}.tooltip-inner{max-width:var(--tblr-tooltip-max-width);padding:var(--tblr-tooltip-padding-y) var(--tblr-tooltip-padding-x);color:var(--tblr-tooltip-color);text-align:center;background-color:var(--tblr-tooltip-bg);border-radius:var(--tblr-tooltip-border-radius)}.popover{--tblr-popover-zindex: 1070;--tblr-popover-max-width: 276px;--tblr-popover-font-size: .765625rem;--tblr-popover-bg: var(--tblr-bg-surface);--tblr-popover-border-width: var(--tblr-border-width);--tblr-popover-border-color: var(--tblr-border-color);--tblr-popover-border-radius: var(--tblr-border-radius-lg);--tblr-popover-inner-border-radius: calc(var(--tblr-border-radius-lg) - var(--tblr-border-width));--tblr-popover-box-shadow: var(--tblr-box-shadow);--tblr-popover-header-padding-x: 1rem;--tblr-popover-header-padding-y: .5rem;--tblr-popover-header-font-size: .875rem;--tblr-popover-header-color: inherit;--tblr-popover-header-bg: transparent;--tblr-popover-body-padding-x: 1rem;--tblr-popover-body-padding-y: 1rem;--tblr-popover-body-color: inherit;--tblr-popover-arrow-width: 1rem;--tblr-popover-arrow-height: .5rem;--tblr-popover-arrow-border: var(--tblr-popover-border-color);z-index:var(--tblr-popover-zindex);display:block;max-width:var(--tblr-popover-max-width);font-family:var(--tblr-font-sans-serif);font-style:normal;font-weight:400;line-height:1.4285714286;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--tblr-popover-font-size);word-wrap:break-word;background-color:var(--tblr-popover-bg);background-clip:padding-box;border:var(--tblr-popover-border-width) solid var(--tblr-popover-border-color);border-radius:var(--tblr-popover-border-radius);box-shadow:var(--tblr-popover-box-shadow)}.popover .popover-arrow{display:block;width:var(--tblr-popover-arrow-width);height:var(--tblr-popover-arrow-height)}.popover .popover-arrow:before,.popover .popover-arrow:after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width))}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{border-width:var(--tblr-popover-arrow-height) calc(var(--tblr-popover-arrow-width) * .5) 0}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before{bottom:0;border-top-color:var(--tblr-popover-arrow-border)}.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{bottom:var(--tblr-popover-border-width);border-top-color:var(--tblr-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width));width:var(--tblr-popover-arrow-height);height:var(--tblr-popover-arrow-width)}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{border-width:calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height) calc(var(--tblr-popover-arrow-width) * .5) 0}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before{left:0;border-right-color:var(--tblr-popover-arrow-border)}.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{left:var(--tblr-popover-border-width);border-right-color:var(--tblr-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width))}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{border-width:0 calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height)}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before{top:0;border-bottom-color:var(--tblr-popover-arrow-border)}.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{top:var(--tblr-popover-border-width);border-bottom-color:var(--tblr-popover-bg)}.bs-popover-bottom .popover-header:before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--tblr-popover-arrow-width);margin-left:calc(-.5 * var(--tblr-popover-arrow-width));content:"";border-bottom:var(--tblr-popover-border-width) solid var(--tblr-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width));width:var(--tblr-popover-arrow-height);height:var(--tblr-popover-arrow-width)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{border-width:calc(var(--tblr-popover-arrow-width) * .5) 0 calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before{right:0;border-left-color:var(--tblr-popover-arrow-border)}.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{right:var(--tblr-popover-border-width);border-left-color:var(--tblr-popover-bg)}.popover-header{padding:var(--tblr-popover-header-padding-y) var(--tblr-popover-header-padding-x);margin-bottom:0;font-size:var(--tblr-popover-header-font-size);color:var(--tblr-popover-header-color);background-color:var(--tblr-popover-header-bg);border-bottom:var(--tblr-popover-border-width) solid var(--tblr-popover-border-color);border-top-left-radius:var(--tblr-popover-inner-border-radius);border-top-right-radius:var(--tblr-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--tblr-popover-body-padding-y) var(--tblr-popover-body-padding-x);color:var(--tblr-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .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:translate(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translate(-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 .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:.5;transition:opacity .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:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:1.5rem;height:1.5rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='15 18 9 12 15 6'%3e%3c/polyline%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='9 18 15 12 9 6'%3e%3c/polyline%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%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-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}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--tblr-spinner-width);height:var(--tblr-spinner-height);vertical-align:var(--tblr-spinner-vertical-align);border-radius:50%;animation:var(--tblr-spinner-animation-speed) linear infinite var(--tblr-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--tblr-spinner-width: 1.5rem;--tblr-spinner-height: 1.5rem;--tblr-spinner-vertical-align: -.125em;--tblr-spinner-border-width: 2px;--tblr-spinner-animation-speed: .75s;--tblr-spinner-animation-name: spinner-border;border:var(--tblr-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--tblr-spinner-width: 1rem;--tblr-spinner-height: 1rem;--tblr-spinner-border-width: 1px}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--tblr-spinner-width: 1.5rem;--tblr-spinner-height: 1.5rem;--tblr-spinner-vertical-align: -.125em;--tblr-spinner-animation-speed: .75s;--tblr-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--tblr-spinner-width: 1rem;--tblr-spinner-height: 1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--tblr-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--tblr-offcanvas-zindex: 1045;--tblr-offcanvas-width: 400px;--tblr-offcanvas-height: 30vh;--tblr-offcanvas-padding-x: 1.5rem;--tblr-offcanvas-padding-y: 1.5rem;--tblr-offcanvas-color: var(--tblr-body-color);--tblr-offcanvas-bg: var(--tblr-bg-surface);--tblr-offcanvas-border-width: var(--tblr-border-width);--tblr-offcanvas-border-color: var(--tblr-border-color);--tblr-offcanvas-box-shadow: var(--tblr-box-shadow-sm);--tblr-offcanvas-transition: transform .3s ease-in-out;--tblr-offcanvas-title-line-height: 1.4285714286}@media (max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 575.98px) and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media (min-width: 576px){.offcanvas-sm{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 767.98px) and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media (min-width: 768px){.offcanvas-md{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 991.98px) and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media (min-width: 992px){.offcanvas-lg{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media (min-width: 1200px){.offcanvas-xl{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media (min-width: 1400px){.offcanvas-xxl{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}@media (prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#182433}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.24}.offcanvas-header{display:flex;align-items:center;padding:var(--tblr-offcanvas-padding-y) var(--tblr-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--tblr-offcanvas-padding-y) * .5) calc(var(--tblr-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--tblr-offcanvas-padding-y)) calc(-.5 * var(--tblr-offcanvas-padding-x)) calc(-.5 * var(--tblr-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--tblr-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--tblr-offcanvas-padding-y) var(--tblr-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.2}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.1}}.placeholder-wave{mask-image:linear-gradient(130deg,#000 55%,#000000e6,#000 95%);mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#f6f8fb!important;background-color:RGBA(var(--tblr-primary-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-secondary,.text-bg-gray{color:#f6f8fb!important;background-color:RGBA(var(--tblr-secondary-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-success{color:#f6f8fb!important;background-color:RGBA(var(--tblr-success-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-info{color:#f6f8fb!important;background-color:RGBA(var(--tblr-info-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-warning{color:#f6f8fb!important;background-color:RGBA(var(--tblr-warning-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-danger{color:#f6f8fb!important;background-color:RGBA(var(--tblr-danger-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-light,.text-bg-white{color:#182433!important;background-color:RGBA(var(--tblr-light-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-dark,.text-bg-black{color:#f6f8fb!important;background-color:RGBA(var(--tblr-dark-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-muted{color:#f6f8fb!important;background-color:RGBA(var(--tblr-muted-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-blue{color:#f6f8fb!important;background-color:RGBA(var(--tblr-blue-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-azure{color:#f6f8fb!important;background-color:RGBA(var(--tblr-azure-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-indigo{color:#f6f8fb!important;background-color:RGBA(var(--tblr-indigo-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-purple{color:#f6f8fb!important;background-color:RGBA(var(--tblr-purple-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-pink{color:#f6f8fb!important;background-color:RGBA(var(--tblr-pink-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-red{color:#f6f8fb!important;background-color:RGBA(var(--tblr-red-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-orange{color:#f6f8fb!important;background-color:RGBA(var(--tblr-orange-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-yellow{color:#f6f8fb!important;background-color:RGBA(var(--tblr-yellow-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-lime{color:#f6f8fb!important;background-color:RGBA(var(--tblr-lime-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-green{color:#f6f8fb!important;background-color:RGBA(var(--tblr-green-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-teal{color:#f6f8fb!important;background-color:RGBA(var(--tblr-teal-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-cyan{color:#f6f8fb!important;background-color:RGBA(var(--tblr-cyan-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-x{color:#f6f8fb!important;background-color:RGBA(var(--tblr-x-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-facebook{color:#f6f8fb!important;background-color:RGBA(var(--tblr-facebook-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-twitter{color:#f6f8fb!important;background-color:RGBA(var(--tblr-twitter-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-linkedin{color:#f6f8fb!important;background-color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-google{color:#f6f8fb!important;background-color:RGBA(var(--tblr-google-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-youtube{color:#f6f8fb!important;background-color:RGBA(var(--tblr-youtube-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-vimeo{color:#f6f8fb!important;background-color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-dribbble{color:#f6f8fb!important;background-color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-github{color:#f6f8fb!important;background-color:RGBA(var(--tblr-github-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-instagram{color:#f6f8fb!important;background-color:RGBA(var(--tblr-instagram-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-pinterest{color:#f6f8fb!important;background-color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-vk{color:#f6f8fb!important;background-color:RGBA(var(--tblr-vk-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-rss{color:#f6f8fb!important;background-color:RGBA(var(--tblr-rss-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-flickr{color:#f6f8fb!important;background-color:RGBA(var(--tblr-flickr-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-bitbucket{color:#f6f8fb!important;background-color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-tabler{color:#f6f8fb!important;background-color:RGBA(var(--tblr-tabler-rgb),var(--tblr-bg-opacity, 1))!important}.link-primary{color:RGBA(var(--tblr-primary-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-primary-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-primary:hover,.link-primary:focus{color:RGBA(0,106,100,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,106,100,var(--tblr-link-underline-opacity, 1))!important}.link-secondary{color:RGBA(var(--tblr-secondary-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-secondary-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86,98,116,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(86,98,116,var(--tblr-link-underline-opacity, 1))!important}.link-success{color:RGBA(var(--tblr-success-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-success-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-success:hover,.link-success:focus{color:RGBA(38,143,54,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(38,143,54,var(--tblr-link-underline-opacity, 1))!important}.link-info{color:RGBA(var(--tblr-info-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-info-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-info:hover,.link-info:focus{color:RGBA(53,122,180,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,122,180,var(--tblr-link-underline-opacity, 1))!important}.link-warning{color:RGBA(var(--tblr-warning-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-warning-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-warning:hover,.link-warning:focus{color:RGBA(198,82,6,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(198,82,6,var(--tblr-link-underline-opacity, 1))!important}.link-danger{color:RGBA(var(--tblr-danger-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-danger-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-danger:hover,.link-danger:focus{color:RGBA(171,46,46,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,46,46,var(--tblr-link-underline-opacity, 1))!important}.link-light{color:RGBA(var(--tblr-light-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-light-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-light:hover,.link-light:focus{color:RGBA(248,249,252,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(248,249,252,var(--tblr-link-underline-opacity, 1))!important}.link-dark{color:RGBA(var(--tblr-dark-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-dark-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-dark:hover,.link-dark:focus{color:RGBA(19,29,41,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,29,41,var(--tblr-link-underline-opacity, 1))!important}.link-muted{color:RGBA(var(--tblr-muted-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-muted-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-muted:hover,.link-muted:focus{color:RGBA(86,98,116,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(86,98,116,var(--tblr-link-underline-opacity, 1))!important}.link-blue{color:RGBA(var(--tblr-blue-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-blue-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-blue:hover,.link-blue:focus{color:RGBA(5,89,167,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(5,89,167,var(--tblr-link-underline-opacity, 1))!important}.link-azure{color:RGBA(var(--tblr-azure-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-azure-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-azure:hover,.link-azure:focus{color:RGBA(53,122,180,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,122,180,var(--tblr-link-underline-opacity, 1))!important}.link-indigo{color:RGBA(var(--tblr-indigo-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-indigo-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-indigo:hover,.link-indigo:focus{color:RGBA(53,79,188,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,79,188,var(--tblr-link-underline-opacity, 1))!important}.link-purple{color:RGBA(var(--tblr-purple-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-purple-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-purple:hover,.link-purple:focus{color:RGBA(139,50,161,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(139,50,161,var(--tblr-link-underline-opacity, 1))!important}.link-pink{color:RGBA(var(--tblr-pink-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-pink-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-pink:hover,.link-pink:focus{color:RGBA(171,41,86,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,41,86,var(--tblr-link-underline-opacity, 1))!important}.link-red{color:RGBA(var(--tblr-red-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-red-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-red:hover,.link-red:focus{color:RGBA(171,46,46,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,46,46,var(--tblr-link-underline-opacity, 1))!important}.link-orange{color:RGBA(var(--tblr-orange-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-orange-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-orange:hover,.link-orange:focus{color:RGBA(198,82,6,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(198,82,6,var(--tblr-link-underline-opacity, 1))!important}.link-yellow{color:RGBA(var(--tblr-yellow-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-yellow-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-yellow:hover,.link-yellow:focus{color:RGBA(196,127,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(196,127,0,var(--tblr-link-underline-opacity, 1))!important}.link-lime{color:RGBA(var(--tblr-lime-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-lime-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-lime:hover,.link-lime:focus{color:RGBA(93,147,18,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(93,147,18,var(--tblr-link-underline-opacity, 1))!important}.link-green{color:RGBA(var(--tblr-green-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-green-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-green:hover,.link-green:focus{color:RGBA(38,143,54,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(38,143,54,var(--tblr-link-underline-opacity, 1))!important}.link-teal{color:RGBA(var(--tblr-teal-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-teal-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-teal:hover,.link-teal:focus{color:RGBA(10,133,96,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(10,133,96,var(--tblr-link-underline-opacity, 1))!important}.link-cyan{color:RGBA(var(--tblr-cyan-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-cyan-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-cyan:hover,.link-cyan:focus{color:RGBA(18,130,147,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(18,130,147,var(--tblr-link-underline-opacity, 1))!important}.link-x{color:RGBA(var(--tblr-x-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-x-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-x:hover,.link-x:focus{color:RGBA(0,0,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,0,0,var(--tblr-link-underline-opacity, 1))!important}.link-facebook{color:RGBA(var(--tblr-facebook-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-facebook-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-facebook:hover,.link-facebook:focus{color:RGBA(19,95,194,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,95,194,var(--tblr-link-underline-opacity, 1))!important}.link-twitter{color:RGBA(var(--tblr-twitter-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-twitter-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-twitter:hover,.link-twitter:focus{color:RGBA(23,129,194,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(23,129,194,var(--tblr-link-underline-opacity, 1))!important}.link-linkedin{color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-linkedin:hover,.link-linkedin:focus{color:RGBA(8,82,155,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(8,82,155,var(--tblr-link-underline-opacity, 1))!important}.link-google{color:RGBA(var(--tblr-google-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-google-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-google:hover,.link-google:focus{color:RGBA(176,62,52,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(176,62,52,var(--tblr-link-underline-opacity, 1))!important}.link-youtube{color:RGBA(var(--tblr-youtube-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-youtube-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-youtube:hover,.link-youtube:focus{color:RGBA(204,0,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(204,0,0,var(--tblr-link-underline-opacity, 1))!important}.link-vimeo{color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-vimeo:hover,.link-vimeo:focus{color:RGBA(21,146,187,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(21,146,187,var(--tblr-link-underline-opacity, 1))!important}.link-dribbble{color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-dribbble:hover,.link-dribbble:focus{color:RGBA(187,61,110,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(187,61,110,var(--tblr-link-underline-opacity, 1))!important}.link-github{color:RGBA(var(--tblr-github-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-github-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-github:hover,.link-github:focus{color:RGBA(19,18,18,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,18,18,var(--tblr-link-underline-opacity, 1))!important}.link-instagram{color:RGBA(var(--tblr-instagram-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-instagram-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-instagram:hover,.link-instagram:focus{color:RGBA(182,51,76,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(182,51,76,var(--tblr-link-underline-opacity, 1))!important}.link-pinterest{color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-pinterest:hover,.link-pinterest:focus{color:RGBA(151,6,22,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(151,6,22,var(--tblr-link-underline-opacity, 1))!important}.link-vk{color:RGBA(var(--tblr-vk-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-vk-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-vk:hover,.link-vk:focus{color:RGBA(79,105,134,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(79,105,134,var(--tblr-link-underline-opacity, 1))!important}.link-rss{color:RGBA(var(--tblr-rss-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-rss-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-rss:hover,.link-rss:focus{color:RGBA(204,132,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(204,132,0,var(--tblr-link-underline-opacity, 1))!important}.link-flickr{color:RGBA(var(--tblr-flickr-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-flickr-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-flickr:hover,.link-flickr:focus{color:RGBA(0,79,176,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,79,176,var(--tblr-link-underline-opacity, 1))!important}.link-bitbucket{color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-bitbucket:hover,.link-bitbucket:focus{color:RGBA(0,66,163,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,66,163,var(--tblr-link-underline-opacity, 1))!important}.link-tabler{color:RGBA(var(--tblr-tabler-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-tabler-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-tabler:hover,.link-tabler:focus{color:RGBA(5,89,167,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(5,89,167,var(--tblr-link-underline-opacity, 1))!important}.link-body-emphasis{color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-opacity, .75))!important;text-decoration-color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-underline-opacity, .75))!important}.focus-ring:focus{outline:0;box-shadow:var(--tblr-focus-ring-x, 0) var(--tblr-focus-ring-y, 0) var(--tblr-focus-ring-blur, 0) var(--tblr-focus-ring-width) var(--tblr-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-opacity, .5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--tblr-icon-link-transform, translate3d(.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--tblr-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--tblr-aspect-ratio: 100%}.ratio-2x1{--tblr-aspect-ratio: 50%}.ratio-1x2{--tblr-aspect-ratio: 200%}.ratio-3x1{--tblr-aspect-ratio: 33.3333333333%}.ratio-1x3{--tblr-aspect-ratio: 300%}.ratio-4x3{--tblr-aspect-ratio: 75%}.ratio-3x4{--tblr-aspect-ratio: 133.3333333333%}.ratio-16x9{--tblr-aspect-ratio: 56.25%}.ratio-9x16{--tblr-aspect-ratio: 177.7777777778%}.ratio-21x9{--tblr-aspect-ratio: 42.8571428571%}.ratio-9x21{--tblr-aspect-ratio: 233.3333333333%}.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:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media (min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){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}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute!important}.stretched-link:after{position:absolute;inset:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--tblr-border-width);min-height:1em;background-color:currentcolor;opacity:.16}.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}.object-fit-contain{object-fit:contain!important}.object-fit-cover{object-fit:cover!important}.object-fit-fill{object-fit:fill!important}.object-fit-scale{object-fit:scale-down!important}.object-fit-none{object-fit:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y: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-inline-grid{display:inline-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:var(--tblr-box-shadow)!important}.shadow-sm{box-shadow:var(--tblr-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--tblr-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--tblr-focus-ring-color: rgba(var(--tblr-primary-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-secondary{--tblr-focus-ring-color: rgba(var(--tblr-secondary-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-success{--tblr-focus-ring-color: rgba(var(--tblr-success-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-info{--tblr-focus-ring-color: rgba(var(--tblr-info-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-warning{--tblr-focus-ring-color: rgba(var(--tblr-warning-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-danger{--tblr-focus-ring-color: rgba(var(--tblr-danger-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-light{--tblr-focus-ring-color: rgba(var(--tblr-light-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-dark{--tblr-focus-ring-color: rgba(var(--tblr-dark-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-muted{--tblr-focus-ring-color: rgba(var(--tblr-muted-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-blue{--tblr-focus-ring-color: rgba(var(--tblr-blue-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-azure{--tblr-focus-ring-color: rgba(var(--tblr-azure-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-indigo{--tblr-focus-ring-color: rgba(var(--tblr-indigo-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-purple{--tblr-focus-ring-color: rgba(var(--tblr-purple-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-pink{--tblr-focus-ring-color: rgba(var(--tblr-pink-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-red{--tblr-focus-ring-color: rgba(var(--tblr-red-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-orange{--tblr-focus-ring-color: rgba(var(--tblr-orange-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-yellow{--tblr-focus-ring-color: rgba(var(--tblr-yellow-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-lime{--tblr-focus-ring-color: rgba(var(--tblr-lime-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-green{--tblr-focus-ring-color: rgba(var(--tblr-green-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-teal{--tblr-focus-ring-color: rgba(var(--tblr-teal-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-cyan{--tblr-focus-ring-color: rgba(var(--tblr-cyan-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-x{--tblr-focus-ring-color: rgba(var(--tblr-x-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-facebook{--tblr-focus-ring-color: rgba(var(--tblr-facebook-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-twitter{--tblr-focus-ring-color: rgba(var(--tblr-twitter-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-linkedin{--tblr-focus-ring-color: rgba(var(--tblr-linkedin-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-google{--tblr-focus-ring-color: rgba(var(--tblr-google-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-youtube{--tblr-focus-ring-color: rgba(var(--tblr-youtube-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-vimeo{--tblr-focus-ring-color: rgba(var(--tblr-vimeo-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-dribbble{--tblr-focus-ring-color: rgba(var(--tblr-dribbble-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-github{--tblr-focus-ring-color: rgba(var(--tblr-github-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-instagram{--tblr-focus-ring-color: rgba(var(--tblr-instagram-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-pinterest{--tblr-focus-ring-color: rgba(var(--tblr-pinterest-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-vk{--tblr-focus-ring-color: rgba(var(--tblr-vk-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-rss{--tblr-focus-ring-color: rgba(var(--tblr-rss-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-flickr{--tblr-focus-ring-color: rgba(var(--tblr-flickr-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-bitbucket{--tblr-focus-ring-color: rgba(var(--tblr-bitbucket-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-tabler{--tblr-focus-ring-color: rgba(var(--tblr-tabler-rgb), var(--tblr-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-wide{border:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-0{border:0!important}.border-top{border-top:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-top-wide{border-top:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-end-wide{border-right:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-bottom-wide{border-bottom:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-start-wide{border-left:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-start-0{border-left:0!important}.border-primary{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-primary-rgb),var(--tblr-border-opacity))!important}.border-secondary{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-secondary-rgb),var(--tblr-border-opacity))!important}.border-success{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-success-rgb),var(--tblr-border-opacity))!important}.border-info{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-info-rgb),var(--tblr-border-opacity))!important}.border-warning{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-warning-rgb),var(--tblr-border-opacity))!important}.border-danger{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-danger-rgb),var(--tblr-border-opacity))!important}.border-light{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-light-rgb),var(--tblr-border-opacity))!important}.border-dark{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-dark-rgb),var(--tblr-border-opacity))!important}.border-muted{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-muted-rgb),var(--tblr-border-opacity))!important}.border-blue{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-blue-rgb),var(--tblr-border-opacity))!important}.border-azure{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-azure-rgb),var(--tblr-border-opacity))!important}.border-indigo{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-indigo-rgb),var(--tblr-border-opacity))!important}.border-purple{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-purple-rgb),var(--tblr-border-opacity))!important}.border-pink{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-pink-rgb),var(--tblr-border-opacity))!important}.border-red{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-red-rgb),var(--tblr-border-opacity))!important}.border-orange{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-orange-rgb),var(--tblr-border-opacity))!important}.border-yellow{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-yellow-rgb),var(--tblr-border-opacity))!important}.border-lime{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-lime-rgb),var(--tblr-border-opacity))!important}.border-green{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-green-rgb),var(--tblr-border-opacity))!important}.border-teal{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-teal-rgb),var(--tblr-border-opacity))!important}.border-cyan{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-cyan-rgb),var(--tblr-border-opacity))!important}.border-x{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-x-rgb),var(--tblr-border-opacity))!important}.border-facebook{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-facebook-rgb),var(--tblr-border-opacity))!important}.border-twitter{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-twitter-rgb),var(--tblr-border-opacity))!important}.border-linkedin{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-border-opacity))!important}.border-google{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-google-rgb),var(--tblr-border-opacity))!important}.border-youtube{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-youtube-rgb),var(--tblr-border-opacity))!important}.border-vimeo{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-border-opacity))!important}.border-dribbble{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-border-opacity))!important}.border-github{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-github-rgb),var(--tblr-border-opacity))!important}.border-instagram{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-instagram-rgb),var(--tblr-border-opacity))!important}.border-pinterest{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-border-opacity))!important}.border-vk{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-vk-rgb),var(--tblr-border-opacity))!important}.border-rss{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-rss-rgb),var(--tblr-border-opacity))!important}.border-flickr{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-flickr-rgb),var(--tblr-border-opacity))!important}.border-bitbucket{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-border-opacity))!important}.border-tabler{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-tabler-rgb),var(--tblr-border-opacity))!important}.border-black{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-black-rgb),var(--tblr-border-opacity))!important}.border-white{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-white-rgb),var(--tblr-border-opacity))!important}.border-primary-subtle{border-color:var(--tblr-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--tblr-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--tblr-success-border-subtle)!important}.border-info-subtle{border-color:var(--tblr-info-border-subtle)!important}.border-warning-subtle{border-color:var(--tblr-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--tblr-danger-border-subtle)!important}.border-light-subtle{border-color:var(--tblr-light-border-subtle)!important}.border-dark-subtle{border-color:var(--tblr-dark-border-subtle)!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}.border-opacity-10{--tblr-border-opacity: .1}.border-opacity-25{--tblr-border-opacity: .25}.border-opacity-50{--tblr-border-opacity: .5}.border-opacity-75{--tblr-border-opacity: .75}.border-opacity-100{--tblr-border-opacity: 1}.w-25{width:25%!important}.w-33{width:33.33333%!important}.w-50{width:50%!important}.w-66{width:66.66666%!important}.w-75{width:75%!important}.w-100{width:100%!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-33{height:33.33333%!important}.h-50{height:50%!important}.h-66{height:66.66666%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:2rem!important}.m-6{margin:3rem!important}.m-7{margin:5rem!important}.m-8{margin:8rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:2rem!important;margin-left:2rem!important}.mx-6{margin-right:3rem!important;margin-left:3rem!important}.mx-7{margin-right:5rem!important;margin-left:5rem!important}.mx-8{margin-right:8rem!important;margin-left:8rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:2rem!important}.mt-6{margin-top:3rem!important}.mt-7{margin-top:5rem!important}.mt-8{margin-top:8rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:2rem!important}.me-6{margin-right:3rem!important}.me-7{margin-right:5rem!important}.me-8{margin-right:8rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:2rem!important}.mb-6{margin-bottom:3rem!important}.mb-7{margin-bottom:5rem!important}.mb-8{margin-bottom:8rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:2rem!important}.ms-6{margin-left:3rem!important}.ms-7{margin-left:5rem!important}.ms-8{margin-left:8rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:2rem!important}.p-6{padding:3rem!important}.p-7{padding:5rem!important}.p-8{padding:8rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:2rem!important;padding-left:2rem!important}.px-6{padding-right:3rem!important;padding-left:3rem!important}.px-7{padding-right:5rem!important;padding-left:5rem!important}.px-8{padding-right:8rem!important;padding-left:8rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:2rem!important}.pt-6{padding-top:3rem!important}.pt-7{padding-top:5rem!important}.pt-8{padding-top:8rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:2rem!important}.pe-6{padding-right:3rem!important}.pe-7{padding-right:5rem!important}.pe-8{padding-right:8rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:2rem!important}.pb-6{padding-bottom:3rem!important}.pb-7{padding-bottom:5rem!important}.pb-8{padding-bottom:8rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:2rem!important}.ps-6{padding-left:3rem!important}.ps-7{padding-left:5rem!important}.ps-8{padding-left:8rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:2rem!important}.gap-6{gap:3rem!important}.gap-7{gap:5rem!important}.gap-8{gap:8rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:2rem!important}.row-gap-6{row-gap:3rem!important}.row-gap-7{row-gap:5rem!important}.row-gap-8{row-gap:8rem!important}.column-gap-0{column-gap:0!important}.column-gap-1{column-gap:.25rem!important}.column-gap-2{column-gap:.5rem!important}.column-gap-3{column-gap:1rem!important}.column-gap-4{column-gap:1.5rem!important}.column-gap-5{column-gap:2rem!important}.column-gap-6{column-gap:3rem!important}.column-gap-7{column-gap:5rem!important}.column-gap-8{column-gap:8rem!important}.font-monospace{font-family:var(--tblr-font-monospace)!important}.fs-1{font-size:1.5rem!important}.fs-2{font-size:1.25rem!important}.fs-3{font-size:1rem!important}.fs-4{font-size:.875rem!important}.fs-5{font-size:.75rem!important}.fs-6{font-size:.625rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold,.fw-bold{font-weight:600!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.1428571429!important}.lh-base{line-height:1.4285714286!important}.lh-lg{line-height:1.7142857143!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-muted{--tblr-text-opacity: 1;color:var(--tblr-secondary-color)!important}.text-black{--tblr-text-opacity: 1;color:rgba(var(--tblr-black-rgb),var(--tblr-text-opacity))!important}.text-white{--tblr-text-opacity: 1;color:rgba(var(--tblr-white-rgb),var(--tblr-text-opacity))!important}.text-body{--tblr-text-opacity: 1;color:rgba(var(--tblr-body-color-rgb),var(--tblr-text-opacity))!important}.text-black-50{--tblr-text-opacity: 1;color:#00000080!important}.text-white-50{--tblr-text-opacity: 1;color:#ffffff80!important}.text-body-secondary{--tblr-text-opacity: 1;color:var(--tblr-secondary-color)!important}.text-body-tertiary{--tblr-text-opacity: 1;color:var(--tblr-tertiary-color)!important}.text-body-emphasis{--tblr-text-opacity: 1;color:var(--tblr-emphasis-color)!important}.text-reset{--tblr-text-opacity: 1;color:inherit!important}.text-opacity-25{--tblr-text-opacity: .25}.text-opacity-50{--tblr-text-opacity: .5}.text-opacity-75{--tblr-text-opacity: .75}.text-opacity-100{--tblr-text-opacity: 1}.text-primary-emphasis{color:var(--tblr-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--tblr-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--tblr-success-text-emphasis)!important}.text-info-emphasis{color:var(--tblr-info-text-emphasis)!important}.text-warning-emphasis{color:var(--tblr-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--tblr-danger-text-emphasis)!important}.text-light-emphasis{color:var(--tblr-light-text-emphasis)!important}.text-dark-emphasis{color:var(--tblr-dark-text-emphasis)!important}.link-opacity-10,.link-opacity-10-hover:hover{--tblr-link-opacity: .1}.link-opacity-25,.link-opacity-25-hover:hover{--tblr-link-opacity: .25}.link-opacity-50,.link-opacity-50-hover:hover{--tblr-link-opacity: .5}.link-opacity-75,.link-opacity-75-hover:hover{--tblr-link-opacity: .75}.link-opacity-100,.link-opacity-100-hover:hover{--tblr-link-opacity: 1}.link-offset-1,.link-offset-1-hover:hover{text-underline-offset:.125em!important}.link-offset-2,.link-offset-2-hover:hover{text-underline-offset:.25em!important}.link-offset-3,.link-offset-3-hover:hover{text-underline-offset:.375em!important}.link-underline-primary{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-primary-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-secondary{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-secondary-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-success{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-success-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-info{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-info-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-warning{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-warning-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-danger{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-danger-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-light{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-light-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-dark{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-dark-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-muted{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-muted-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-blue{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-blue-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-azure{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-azure-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-indigo{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-indigo-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-purple{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-purple-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-pink{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-pink-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-red{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-red-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-orange{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-orange-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-yellow{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-yellow-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-lime{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-lime-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-green{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-green-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-teal{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-teal-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-cyan{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-cyan-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-x{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-x-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-facebook{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-facebook-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-twitter{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-twitter-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-linkedin{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-google{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-google-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-youtube{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-youtube-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-vimeo{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-dribbble{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-github{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-github-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-instagram{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-instagram-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-pinterest{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-vk{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-vk-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-rss{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-rss-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-flickr{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-flickr-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-bitbucket{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-tabler{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-tabler-rgb),var(--tblr-link-underline-opacity))!important}.link-underline{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-underline-opacity-0,.link-underline-opacity-0-hover:hover{--tblr-link-underline-opacity: 0}.link-underline-opacity-10,.link-underline-opacity-10-hover:hover{--tblr-link-underline-opacity: .1}.link-underline-opacity-25,.link-underline-opacity-25-hover:hover{--tblr-link-underline-opacity: .25}.link-underline-opacity-50,.link-underline-opacity-50-hover:hover{--tblr-link-underline-opacity: .5}.link-underline-opacity-75,.link-underline-opacity-75-hover:hover{--tblr-link-underline-opacity: .75}.link-underline-opacity-100,.link-underline-opacity-100-hover:hover{--tblr-link-underline-opacity: 1}.bg-black{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-black-rgb),var(--tblr-bg-opacity))!important}.bg-body{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-body-bg-rgb),var(--tblr-bg-opacity))!important}.bg-transparent{--tblr-bg-opacity: 1;background-color:transparent!important}.bg-body-secondary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-secondary-bg-rgb),var(--tblr-bg-opacity))!important}.bg-body-tertiary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-tertiary-bg-rgb),var(--tblr-bg-opacity))!important}.bg-opacity-10{--tblr-bg-opacity: .1}.bg-opacity-25{--tblr-bg-opacity: .25}.bg-opacity-50{--tblr-bg-opacity: .5}.bg-opacity-75{--tblr-bg-opacity: .75}.bg-opacity-100{--tblr-bg-opacity: 1}.bg-primary-subtle{background-color:var(--tblr-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--tblr-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--tblr-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--tblr-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--tblr-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--tblr-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--tblr-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--tblr-dark-bg-subtle)!important}.bg-gradient{background-image:var(--tblr-gradient)!important}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--tblr-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--tblr-border-radius-sm)!important}.rounded-2{border-radius:var(--tblr-border-radius)!important}.rounded-3{border-radius:var(--tblr-border-radius-lg)!important}.rounded-4{border-radius:var(--tblr-border-radius-xl)!important}.rounded-5{border-radius:var(--tblr-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--tblr-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--tblr-border-radius)!important;border-top-right-radius:var(--tblr-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--tblr-border-radius-sm)!important;border-top-right-radius:var(--tblr-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--tblr-border-radius)!important;border-top-right-radius:var(--tblr-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--tblr-border-radius-lg)!important;border-top-right-radius:var(--tblr-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--tblr-border-radius-xl)!important;border-top-right-radius:var(--tblr-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--tblr-border-radius-xxl)!important;border-top-right-radius:var(--tblr-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--tblr-border-radius-pill)!important;border-top-right-radius:var(--tblr-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--tblr-border-radius)!important;border-bottom-right-radius:var(--tblr-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--tblr-border-radius-sm)!important;border-bottom-right-radius:var(--tblr-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--tblr-border-radius)!important;border-bottom-right-radius:var(--tblr-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--tblr-border-radius-lg)!important;border-bottom-right-radius:var(--tblr-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--tblr-border-radius-xl)!important;border-bottom-right-radius:var(--tblr-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--tblr-border-radius-xxl)!important;border-bottom-right-radius:var(--tblr-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--tblr-border-radius-pill)!important;border-bottom-right-radius:var(--tblr-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--tblr-border-radius)!important;border-bottom-left-radius:var(--tblr-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--tblr-border-radius-sm)!important;border-bottom-left-radius:var(--tblr-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--tblr-border-radius)!important;border-bottom-left-radius:var(--tblr-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--tblr-border-radius-lg)!important;border-bottom-left-radius:var(--tblr-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--tblr-border-radius-xl)!important;border-bottom-left-radius:var(--tblr-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--tblr-border-radius-xxl)!important;border-bottom-left-radius:var(--tblr-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--tblr-border-radius-pill)!important;border-bottom-left-radius:var(--tblr-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--tblr-border-radius)!important;border-top-left-radius:var(--tblr-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--tblr-border-radius-sm)!important;border-top-left-radius:var(--tblr-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--tblr-border-radius)!important;border-top-left-radius:var(--tblr-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--tblr-border-radius-lg)!important;border-top-left-radius:var(--tblr-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--tblr-border-radius-xl)!important;border-top-left-radius:var(--tblr-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--tblr-border-radius-xxl)!important;border-top-left-radius:var(--tblr-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--tblr-border-radius-pill)!important;border-top-left-radius:var(--tblr-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}.object-contain{object-fit:contain!important}.object-cover{object-fit:cover!important}.object-fill{object-fit:fill!important}.object-scale-down{object-fit:scale-down!important}.object-none{object-fit:none!important}.tracking-tight{letter-spacing:-.05em!important}.tracking-normal{letter-spacing:0!important}.tracking-wide{letter-spacing:.05em!important}.cursor-auto{cursor:auto!important}.cursor-pointer{cursor:pointer!important}.cursor-move{cursor:move!important}.cursor-not-allowed{cursor:not-allowed!important}.cursor-zoom-in{cursor:zoom-in!important}.cursor-zoom-out{cursor:zoom-out!important}.cursor-default{cursor:default!important}.cursor-none{cursor:none!important}.cursor-help{cursor:help!important}.cursor-progress{cursor:progress!important}.cursor-wait{cursor:wait!important}.cursor-text{cursor:text!important}.cursor-v-text{cursor:vertical-text!important}.cursor-grab{cursor:grab!important}.cursor-grabbing{cursor:grabbing!important}.border-x{border-left:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important;border-right:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-x-wide{border-left:2px var(--tblr-border-style) rgba(4,32,69,.1)!important;border-right:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-x-0{border-left:0!important;border-right:0!important}.border-y{border-top:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important;border-bottom:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-y-wide{border-top:2px var(--tblr-border-style) rgba(4,32,69,.1)!important;border-bottom:2px var(--tblr-border-style) rgba(4,32,69,.1)!important}.border-y-0{border-top:0!important;border-bottom:0!important}.columns-2{columns:2!important}.columns-3{columns:3!important}.columns-4{columns:4!important}@media (min-width: 576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{object-fit:contain!important}.object-fit-sm-cover{object-fit:cover!important}.object-fit-sm-fill{object-fit:fill!important}.object-fit-sm-scale{object-fit:scale-down!important}.object-fit-sm-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:2rem!important}.m-sm-6{margin:3rem!important}.m-sm-7{margin:5rem!important}.m-sm-8{margin:8rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:2rem!important;margin-left:2rem!important}.mx-sm-6{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-7{margin-right:5rem!important;margin-left:5rem!important}.mx-sm-8{margin-right:8rem!important;margin-left:8rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-sm-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-sm-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:2rem!important}.mt-sm-6{margin-top:3rem!important}.mt-sm-7{margin-top:5rem!important}.mt-sm-8{margin-top:8rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:2rem!important}.me-sm-6{margin-right:3rem!important}.me-sm-7{margin-right:5rem!important}.me-sm-8{margin-right:8rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:2rem!important}.mb-sm-6{margin-bottom:3rem!important}.mb-sm-7{margin-bottom:5rem!important}.mb-sm-8{margin-bottom:8rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:2rem!important}.ms-sm-6{margin-left:3rem!important}.ms-sm-7{margin-left:5rem!important}.ms-sm-8{margin-left:8rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:2rem!important}.p-sm-6{padding:3rem!important}.p-sm-7{padding:5rem!important}.p-sm-8{padding:8rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:2rem!important;padding-left:2rem!important}.px-sm-6{padding-right:3rem!important;padding-left:3rem!important}.px-sm-7{padding-right:5rem!important;padding-left:5rem!important}.px-sm-8{padding-right:8rem!important;padding-left:8rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-sm-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-sm-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-sm-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:2rem!important}.pt-sm-6{padding-top:3rem!important}.pt-sm-7{padding-top:5rem!important}.pt-sm-8{padding-top:8rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:2rem!important}.pe-sm-6{padding-right:3rem!important}.pe-sm-7{padding-right:5rem!important}.pe-sm-8{padding-right:8rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:2rem!important}.pb-sm-6{padding-bottom:3rem!important}.pb-sm-7{padding-bottom:5rem!important}.pb-sm-8{padding-bottom:8rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:2rem!important}.ps-sm-6{padding-left:3rem!important}.ps-sm-7{padding-left:5rem!important}.ps-sm-8{padding-left:8rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:2rem!important}.gap-sm-6{gap:3rem!important}.gap-sm-7{gap:5rem!important}.gap-sm-8{gap:8rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:2rem!important}.row-gap-sm-6{row-gap:3rem!important}.row-gap-sm-7{row-gap:5rem!important}.row-gap-sm-8{row-gap:8rem!important}.column-gap-sm-0{column-gap:0!important}.column-gap-sm-1{column-gap:.25rem!important}.column-gap-sm-2{column-gap:.5rem!important}.column-gap-sm-3{column-gap:1rem!important}.column-gap-sm-4{column-gap:1.5rem!important}.column-gap-sm-5{column-gap:2rem!important}.column-gap-sm-6{column-gap:3rem!important}.column-gap-sm-7{column-gap:5rem!important}.column-gap-sm-8{column-gap:8rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}.columns-sm-2{columns:2!important}.columns-sm-3{columns:3!important}.columns-sm-4{columns:4!important}}@media (min-width: 768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{object-fit:contain!important}.object-fit-md-cover{object-fit:cover!important}.object-fit-md-fill{object-fit:fill!important}.object-fit-md-scale{object-fit:scale-down!important}.object-fit-md-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:2rem!important}.m-md-6{margin:3rem!important}.m-md-7{margin:5rem!important}.m-md-8{margin:8rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:2rem!important;margin-left:2rem!important}.mx-md-6{margin-right:3rem!important;margin-left:3rem!important}.mx-md-7{margin-right:5rem!important;margin-left:5rem!important}.mx-md-8{margin-right:8rem!important;margin-left:8rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-md-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-md-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:2rem!important}.mt-md-6{margin-top:3rem!important}.mt-md-7{margin-top:5rem!important}.mt-md-8{margin-top:8rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:2rem!important}.me-md-6{margin-right:3rem!important}.me-md-7{margin-right:5rem!important}.me-md-8{margin-right:8rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:2rem!important}.mb-md-6{margin-bottom:3rem!important}.mb-md-7{margin-bottom:5rem!important}.mb-md-8{margin-bottom:8rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:2rem!important}.ms-md-6{margin-left:3rem!important}.ms-md-7{margin-left:5rem!important}.ms-md-8{margin-left:8rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:2rem!important}.p-md-6{padding:3rem!important}.p-md-7{padding:5rem!important}.p-md-8{padding:8rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:2rem!important;padding-left:2rem!important}.px-md-6{padding-right:3rem!important;padding-left:3rem!important}.px-md-7{padding-right:5rem!important;padding-left:5rem!important}.px-md-8{padding-right:8rem!important;padding-left:8rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-md-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-md-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-md-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:2rem!important}.pt-md-6{padding-top:3rem!important}.pt-md-7{padding-top:5rem!important}.pt-md-8{padding-top:8rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:2rem!important}.pe-md-6{padding-right:3rem!important}.pe-md-7{padding-right:5rem!important}.pe-md-8{padding-right:8rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:2rem!important}.pb-md-6{padding-bottom:3rem!important}.pb-md-7{padding-bottom:5rem!important}.pb-md-8{padding-bottom:8rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:2rem!important}.ps-md-6{padding-left:3rem!important}.ps-md-7{padding-left:5rem!important}.ps-md-8{padding-left:8rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:2rem!important}.gap-md-6{gap:3rem!important}.gap-md-7{gap:5rem!important}.gap-md-8{gap:8rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:2rem!important}.row-gap-md-6{row-gap:3rem!important}.row-gap-md-7{row-gap:5rem!important}.row-gap-md-8{row-gap:8rem!important}.column-gap-md-0{column-gap:0!important}.column-gap-md-1{column-gap:.25rem!important}.column-gap-md-2{column-gap:.5rem!important}.column-gap-md-3{column-gap:1rem!important}.column-gap-md-4{column-gap:1.5rem!important}.column-gap-md-5{column-gap:2rem!important}.column-gap-md-6{column-gap:3rem!important}.column-gap-md-7{column-gap:5rem!important}.column-gap-md-8{column-gap:8rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}.columns-md-2{columns:2!important}.columns-md-3{columns:3!important}.columns-md-4{columns:4!important}}@media (min-width: 992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{object-fit:contain!important}.object-fit-lg-cover{object-fit:cover!important}.object-fit-lg-fill{object-fit:fill!important}.object-fit-lg-scale{object-fit:scale-down!important}.object-fit-lg-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:2rem!important}.m-lg-6{margin:3rem!important}.m-lg-7{margin:5rem!important}.m-lg-8{margin:8rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:2rem!important;margin-left:2rem!important}.mx-lg-6{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-7{margin-right:5rem!important;margin-left:5rem!important}.mx-lg-8{margin-right:8rem!important;margin-left:8rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-lg-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-lg-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:2rem!important}.mt-lg-6{margin-top:3rem!important}.mt-lg-7{margin-top:5rem!important}.mt-lg-8{margin-top:8rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:2rem!important}.me-lg-6{margin-right:3rem!important}.me-lg-7{margin-right:5rem!important}.me-lg-8{margin-right:8rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:2rem!important}.mb-lg-6{margin-bottom:3rem!important}.mb-lg-7{margin-bottom:5rem!important}.mb-lg-8{margin-bottom:8rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:2rem!important}.ms-lg-6{margin-left:3rem!important}.ms-lg-7{margin-left:5rem!important}.ms-lg-8{margin-left:8rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:2rem!important}.p-lg-6{padding:3rem!important}.p-lg-7{padding:5rem!important}.p-lg-8{padding:8rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:2rem!important;padding-left:2rem!important}.px-lg-6{padding-right:3rem!important;padding-left:3rem!important}.px-lg-7{padding-right:5rem!important;padding-left:5rem!important}.px-lg-8{padding-right:8rem!important;padding-left:8rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-lg-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-lg-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-lg-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:2rem!important}.pt-lg-6{padding-top:3rem!important}.pt-lg-7{padding-top:5rem!important}.pt-lg-8{padding-top:8rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:2rem!important}.pe-lg-6{padding-right:3rem!important}.pe-lg-7{padding-right:5rem!important}.pe-lg-8{padding-right:8rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:2rem!important}.pb-lg-6{padding-bottom:3rem!important}.pb-lg-7{padding-bottom:5rem!important}.pb-lg-8{padding-bottom:8rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:2rem!important}.ps-lg-6{padding-left:3rem!important}.ps-lg-7{padding-left:5rem!important}.ps-lg-8{padding-left:8rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:2rem!important}.gap-lg-6{gap:3rem!important}.gap-lg-7{gap:5rem!important}.gap-lg-8{gap:8rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:2rem!important}.row-gap-lg-6{row-gap:3rem!important}.row-gap-lg-7{row-gap:5rem!important}.row-gap-lg-8{row-gap:8rem!important}.column-gap-lg-0{column-gap:0!important}.column-gap-lg-1{column-gap:.25rem!important}.column-gap-lg-2{column-gap:.5rem!important}.column-gap-lg-3{column-gap:1rem!important}.column-gap-lg-4{column-gap:1.5rem!important}.column-gap-lg-5{column-gap:2rem!important}.column-gap-lg-6{column-gap:3rem!important}.column-gap-lg-7{column-gap:5rem!important}.column-gap-lg-8{column-gap:8rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}.columns-lg-2{columns:2!important}.columns-lg-3{columns:3!important}.columns-lg-4{columns:4!important}}@media (min-width: 1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{object-fit:contain!important}.object-fit-xl-cover{object-fit:cover!important}.object-fit-xl-fill{object-fit:fill!important}.object-fit-xl-scale{object-fit:scale-down!important}.object-fit-xl-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:2rem!important}.m-xl-6{margin:3rem!important}.m-xl-7{margin:5rem!important}.m-xl-8{margin:8rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:2rem!important;margin-left:2rem!important}.mx-xl-6{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-7{margin-right:5rem!important;margin-left:5rem!important}.mx-xl-8{margin-right:8rem!important;margin-left:8rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-xl-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-xl-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:2rem!important}.mt-xl-6{margin-top:3rem!important}.mt-xl-7{margin-top:5rem!important}.mt-xl-8{margin-top:8rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:2rem!important}.me-xl-6{margin-right:3rem!important}.me-xl-7{margin-right:5rem!important}.me-xl-8{margin-right:8rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:2rem!important}.mb-xl-6{margin-bottom:3rem!important}.mb-xl-7{margin-bottom:5rem!important}.mb-xl-8{margin-bottom:8rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:2rem!important}.ms-xl-6{margin-left:3rem!important}.ms-xl-7{margin-left:5rem!important}.ms-xl-8{margin-left:8rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:2rem!important}.p-xl-6{padding:3rem!important}.p-xl-7{padding:5rem!important}.p-xl-8{padding:8rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:2rem!important;padding-left:2rem!important}.px-xl-6{padding-right:3rem!important;padding-left:3rem!important}.px-xl-7{padding-right:5rem!important;padding-left:5rem!important}.px-xl-8{padding-right:8rem!important;padding-left:8rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-xl-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-xl-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-xl-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:2rem!important}.pt-xl-6{padding-top:3rem!important}.pt-xl-7{padding-top:5rem!important}.pt-xl-8{padding-top:8rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:2rem!important}.pe-xl-6{padding-right:3rem!important}.pe-xl-7{padding-right:5rem!important}.pe-xl-8{padding-right:8rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:2rem!important}.pb-xl-6{padding-bottom:3rem!important}.pb-xl-7{padding-bottom:5rem!important}.pb-xl-8{padding-bottom:8rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:2rem!important}.ps-xl-6{padding-left:3rem!important}.ps-xl-7{padding-left:5rem!important}.ps-xl-8{padding-left:8rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:2rem!important}.gap-xl-6{gap:3rem!important}.gap-xl-7{gap:5rem!important}.gap-xl-8{gap:8rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:2rem!important}.row-gap-xl-6{row-gap:3rem!important}.row-gap-xl-7{row-gap:5rem!important}.row-gap-xl-8{row-gap:8rem!important}.column-gap-xl-0{column-gap:0!important}.column-gap-xl-1{column-gap:.25rem!important}.column-gap-xl-2{column-gap:.5rem!important}.column-gap-xl-3{column-gap:1rem!important}.column-gap-xl-4{column-gap:1.5rem!important}.column-gap-xl-5{column-gap:2rem!important}.column-gap-xl-6{column-gap:3rem!important}.column-gap-xl-7{column-gap:5rem!important}.column-gap-xl-8{column-gap:8rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}.columns-xl-2{columns:2!important}.columns-xl-3{columns:3!important}.columns-xl-4{columns:4!important}}@media (min-width: 1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{object-fit:contain!important}.object-fit-xxl-cover{object-fit:cover!important}.object-fit-xxl-fill{object-fit:fill!important}.object-fit-xxl-scale{object-fit:scale-down!important}.object-fit-xxl-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:2rem!important}.m-xxl-6{margin:3rem!important}.m-xxl-7{margin:5rem!important}.m-xxl-8{margin:8rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:2rem!important;margin-left:2rem!important}.mx-xxl-6{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-7{margin-right:5rem!important;margin-left:5rem!important}.mx-xxl-8{margin-right:8rem!important;margin-left:8rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-xxl-6{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-7{margin-top:5rem!important;margin-bottom:5rem!important}.my-xxl-8{margin-top:8rem!important;margin-bottom:8rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:2rem!important}.mt-xxl-6{margin-top:3rem!important}.mt-xxl-7{margin-top:5rem!important}.mt-xxl-8{margin-top:8rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:2rem!important}.me-xxl-6{margin-right:3rem!important}.me-xxl-7{margin-right:5rem!important}.me-xxl-8{margin-right:8rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:2rem!important}.mb-xxl-6{margin-bottom:3rem!important}.mb-xxl-7{margin-bottom:5rem!important}.mb-xxl-8{margin-bottom:8rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:2rem!important}.ms-xxl-6{margin-left:3rem!important}.ms-xxl-7{margin-left:5rem!important}.ms-xxl-8{margin-left:8rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:2rem!important}.p-xxl-6{padding:3rem!important}.p-xxl-7{padding:5rem!important}.p-xxl-8{padding:8rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:2rem!important;padding-left:2rem!important}.px-xxl-6{padding-right:3rem!important;padding-left:3rem!important}.px-xxl-7{padding-right:5rem!important;padding-left:5rem!important}.px-xxl-8{padding-right:8rem!important;padding-left:8rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-xxl-6{padding-top:3rem!important;padding-bottom:3rem!important}.py-xxl-7{padding-top:5rem!important;padding-bottom:5rem!important}.py-xxl-8{padding-top:8rem!important;padding-bottom:8rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:2rem!important}.pt-xxl-6{padding-top:3rem!important}.pt-xxl-7{padding-top:5rem!important}.pt-xxl-8{padding-top:8rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:2rem!important}.pe-xxl-6{padding-right:3rem!important}.pe-xxl-7{padding-right:5rem!important}.pe-xxl-8{padding-right:8rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:2rem!important}.pb-xxl-6{padding-bottom:3rem!important}.pb-xxl-7{padding-bottom:5rem!important}.pb-xxl-8{padding-bottom:8rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:2rem!important}.ps-xxl-6{padding-left:3rem!important}.ps-xxl-7{padding-left:5rem!important}.ps-xxl-8{padding-left:8rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:2rem!important}.gap-xxl-6{gap:3rem!important}.gap-xxl-7{gap:5rem!important}.gap-xxl-8{gap:8rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:2rem!important}.row-gap-xxl-6{row-gap:3rem!important}.row-gap-xxl-7{row-gap:5rem!important}.row-gap-xxl-8{row-gap:8rem!important}.column-gap-xxl-0{column-gap:0!important}.column-gap-xxl-1{column-gap:.25rem!important}.column-gap-xxl-2{column-gap:.5rem!important}.column-gap-xxl-3{column-gap:1rem!important}.column-gap-xxl-4{column-gap:1.5rem!important}.column-gap-xxl-5{column-gap:2rem!important}.column-gap-xxl-6{column-gap:3rem!important}.column-gap-xxl-7{column-gap:5rem!important}.column-gap-xxl-8{column-gap:8rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}.columns-xxl-2{columns:2!important}.columns-xxl-3{columns:3!important}.columns-xxl-4{columns:4!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-inline-grid{display:inline-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}}:root,:host{font-size:16px;height:100%}:root,:host,[data-bs-theme=light]{--tblr-primary: #00857D;--tblr-primary-rgb: 0, 133, 125;--tblr-primary-fg: var(--tblr-light);--tblr-primary-darken: #007871;--tblr-primary-lt: #e6f3f2;--tblr-primary-lt-rgb: 230, 243, 242;--tblr-secondary: #6c7a91;--tblr-secondary-rgb: 108, 122, 145;--tblr-secondary-fg: var(--tblr-light);--tblr-secondary-darken: #616e83;--tblr-secondary-lt: #f0f2f4;--tblr-secondary-lt-rgb: 240, 242, 244;--tblr-success: #2fb344;--tblr-success-rgb: 47, 179, 68;--tblr-success-fg: var(--tblr-light);--tblr-success-darken: #2aa13d;--tblr-success-lt: #eaf7ec;--tblr-success-lt-rgb: 234, 247, 236;--tblr-info: #4299e1;--tblr-info-rgb: 66, 153, 225;--tblr-info-fg: var(--tblr-light);--tblr-info-darken: #3b8acb;--tblr-info-lt: #ecf5fc;--tblr-info-lt-rgb: 236, 245, 252;--tblr-warning: #f76707;--tblr-warning-rgb: 247, 103, 7;--tblr-warning-fg: var(--tblr-light);--tblr-warning-darken: #de5d06;--tblr-warning-lt: #fef0e6;--tblr-warning-lt-rgb: 254, 240, 230;--tblr-danger: #d63939;--tblr-danger-rgb: 214, 57, 57;--tblr-danger-fg: var(--tblr-light);--tblr-danger-darken: #c13333;--tblr-danger-lt: #fbebeb;--tblr-danger-lt-rgb: 251, 235, 235;--tblr-light: #f6f8fb;--tblr-light-rgb: 246, 248, 251;--tblr-light-fg: var(--tblr-dark);--tblr-light-darken: #dddfe2;--tblr-light-lt: #fefeff;--tblr-light-lt-rgb: 254, 254, 255;--tblr-dark: #182433;--tblr-dark-rgb: 24, 36, 51;--tblr-dark-fg: var(--tblr-light);--tblr-dark-darken: #16202e;--tblr-dark-lt: #e8e9eb;--tblr-dark-lt-rgb: 232, 233, 235;--tblr-muted: #6c7a91;--tblr-muted-rgb: 108, 122, 145;--tblr-muted-fg: var(--tblr-light);--tblr-muted-darken: #616e83;--tblr-muted-lt: #f0f2f4;--tblr-muted-lt-rgb: 240, 242, 244;--tblr-blue: #066fd1;--tblr-blue-rgb: 6, 111, 209;--tblr-blue-fg: var(--tblr-light);--tblr-blue-darken: #0564bc;--tblr-blue-lt: #e6f1fa;--tblr-blue-lt-rgb: 230, 241, 250;--tblr-azure: #4299e1;--tblr-azure-rgb: 66, 153, 225;--tblr-azure-fg: var(--tblr-light);--tblr-azure-darken: #3b8acb;--tblr-azure-lt: #ecf5fc;--tblr-azure-lt-rgb: 236, 245, 252;--tblr-indigo: #4263eb;--tblr-indigo-rgb: 66, 99, 235;--tblr-indigo-fg: var(--tblr-light);--tblr-indigo-darken: #3b59d4;--tblr-indigo-lt: #eceffd;--tblr-indigo-lt-rgb: 236, 239, 253;--tblr-purple: #ae3ec9;--tblr-purple-rgb: 174, 62, 201;--tblr-purple-fg: var(--tblr-light);--tblr-purple-darken: #9d38b5;--tblr-purple-lt: #f7ecfa;--tblr-purple-lt-rgb: 247, 236, 250;--tblr-pink: #d6336c;--tblr-pink-rgb: 214, 51, 108;--tblr-pink-fg: var(--tblr-light);--tblr-pink-darken: #c12e61;--tblr-pink-lt: #fbebf0;--tblr-pink-lt-rgb: 251, 235, 240;--tblr-red: #d63939;--tblr-red-rgb: 214, 57, 57;--tblr-red-fg: var(--tblr-light);--tblr-red-darken: #c13333;--tblr-red-lt: #fbebeb;--tblr-red-lt-rgb: 251, 235, 235;--tblr-orange: #f76707;--tblr-orange-rgb: 247, 103, 7;--tblr-orange-fg: var(--tblr-light);--tblr-orange-darken: #de5d06;--tblr-orange-lt: #fef0e6;--tblr-orange-lt-rgb: 254, 240, 230;--tblr-yellow: #f59f00;--tblr-yellow-rgb: 245, 159, 0;--tblr-yellow-fg: var(--tblr-light);--tblr-yellow-darken: #dd8f00;--tblr-yellow-lt: #fef5e6;--tblr-yellow-lt-rgb: 254, 245, 230;--tblr-lime: #74b816;--tblr-lime-rgb: 116, 184, 22;--tblr-lime-fg: var(--tblr-light);--tblr-lime-darken: #68a614;--tblr-lime-lt: #f1f8e8;--tblr-lime-lt-rgb: 241, 248, 232;--tblr-green: #2fb344;--tblr-green-rgb: 47, 179, 68;--tblr-green-fg: var(--tblr-light);--tblr-green-darken: #2aa13d;--tblr-green-lt: #eaf7ec;--tblr-green-lt-rgb: 234, 247, 236;--tblr-teal: #0ca678;--tblr-teal-rgb: 12, 166, 120;--tblr-teal-fg: var(--tblr-light);--tblr-teal-darken: #0b956c;--tblr-teal-lt: #e7f6f2;--tblr-teal-lt-rgb: 231, 246, 242;--tblr-cyan: #17a2b8;--tblr-cyan-rgb: 23, 162, 184;--tblr-cyan-fg: var(--tblr-light);--tblr-cyan-darken: #1592a6;--tblr-cyan-lt: #e8f6f8;--tblr-cyan-lt-rgb: 232, 246, 248;--tblr-x: #000000;--tblr-x-rgb: 0, 0, 0;--tblr-x-fg: var(--tblr-light);--tblr-x-darken: black;--tblr-x-lt: #e6e6e6;--tblr-x-lt-rgb: 230, 230, 230;--tblr-facebook: #1877f2;--tblr-facebook-rgb: 24, 119, 242;--tblr-facebook-fg: var(--tblr-light);--tblr-facebook-darken: #166bda;--tblr-facebook-lt: #e8f1fe;--tblr-facebook-lt-rgb: 232, 241, 254;--tblr-twitter: #1da1f2;--tblr-twitter-rgb: 29, 161, 242;--tblr-twitter-fg: var(--tblr-light);--tblr-twitter-darken: #1a91da;--tblr-twitter-lt: #e8f6fe;--tblr-twitter-lt-rgb: 232, 246, 254;--tblr-linkedin: #0a66c2;--tblr-linkedin-rgb: 10, 102, 194;--tblr-linkedin-fg: var(--tblr-light);--tblr-linkedin-darken: #095caf;--tblr-linkedin-lt: #e7f0f9;--tblr-linkedin-lt-rgb: 231, 240, 249;--tblr-google: #dc4e41;--tblr-google-rgb: 220, 78, 65;--tblr-google-fg: var(--tblr-light);--tblr-google-darken: #c6463b;--tblr-google-lt: #fcedec;--tblr-google-lt-rgb: 252, 237, 236;--tblr-youtube: #ff0000;--tblr-youtube-rgb: 255, 0, 0;--tblr-youtube-fg: var(--tblr-light);--tblr-youtube-darken: #e60000;--tblr-youtube-lt: #ffe6e6;--tblr-youtube-lt-rgb: 255, 230, 230;--tblr-vimeo: #1ab7ea;--tblr-vimeo-rgb: 26, 183, 234;--tblr-vimeo-fg: var(--tblr-light);--tblr-vimeo-darken: #17a5d3;--tblr-vimeo-lt: #e8f8fd;--tblr-vimeo-lt-rgb: 232, 248, 253;--tblr-dribbble: #ea4c89;--tblr-dribbble-rgb: 234, 76, 137;--tblr-dribbble-fg: var(--tblr-light);--tblr-dribbble-darken: #d3447b;--tblr-dribbble-lt: #fdedf3;--tblr-dribbble-lt-rgb: 253, 237, 243;--tblr-github: #181717;--tblr-github-rgb: 24, 23, 23;--tblr-github-fg: var(--tblr-light);--tblr-github-darken: #161515;--tblr-github-lt: #e8e8e8;--tblr-github-lt-rgb: 232, 232, 232;--tblr-instagram: #e4405f;--tblr-instagram-rgb: 228, 64, 95;--tblr-instagram-fg: var(--tblr-light);--tblr-instagram-darken: #cd3a56;--tblr-instagram-lt: #fcecef;--tblr-instagram-lt-rgb: 252, 236, 239;--tblr-pinterest: #bd081c;--tblr-pinterest-rgb: 189, 8, 28;--tblr-pinterest-fg: var(--tblr-light);--tblr-pinterest-darken: #aa0719;--tblr-pinterest-lt: #f8e6e8;--tblr-pinterest-lt-rgb: 248, 230, 232;--tblr-vk: #6383a8;--tblr-vk-rgb: 99, 131, 168;--tblr-vk-fg: var(--tblr-light);--tblr-vk-darken: #597697;--tblr-vk-lt: #eff3f6;--tblr-vk-lt-rgb: 239, 243, 246;--tblr-rss: #ffa500;--tblr-rss-rgb: 255, 165, 0;--tblr-rss-fg: var(--tblr-light);--tblr-rss-darken: #e69500;--tblr-rss-lt: #fff6e6;--tblr-rss-lt-rgb: 255, 246, 230;--tblr-flickr: #0063dc;--tblr-flickr-rgb: 0, 99, 220;--tblr-flickr-fg: var(--tblr-light);--tblr-flickr-darken: #0059c6;--tblr-flickr-lt: #e6effc;--tblr-flickr-lt-rgb: 230, 239, 252;--tblr-bitbucket: #0052cc;--tblr-bitbucket-rgb: 0, 82, 204;--tblr-bitbucket-fg: var(--tblr-light);--tblr-bitbucket-darken: #004ab8;--tblr-bitbucket-lt: #e6eefa;--tblr-bitbucket-lt-rgb: 230, 238, 250;--tblr-tabler: #066fd1;--tblr-tabler-rgb: 6, 111, 209;--tblr-tabler-fg: var(--tblr-light);--tblr-tabler-darken: #0564bc;--tblr-tabler-lt: #e6f1fa;--tblr-tabler-lt-rgb: 230, 241, 250;--tblr-gray-50: #f6f8fb;--tblr-gray-50-rgb: 246, 248, 251;--tblr-gray-50-fg: var(--tblr-dark);--tblr-gray-50-darken: #dddfe2;--tblr-gray-50-lt: #fefeff;--tblr-gray-50-lt-rgb: 254, 254, 255;--tblr-gray-100: #eef3f6;--tblr-gray-100-rgb: 238, 243, 246;--tblr-gray-100-fg: var(--tblr-dark);--tblr-gray-100-darken: #d6dbdd;--tblr-gray-100-lt: #fdfefe;--tblr-gray-100-lt-rgb: 253, 254, 254;--tblr-gray-200: #dce1e7;--tblr-gray-200-rgb: 220, 225, 231;--tblr-gray-200-fg: var(--tblr-dark);--tblr-gray-200-darken: #c6cbd0;--tblr-gray-200-lt: #fcfcfd;--tblr-gray-200-lt-rgb: 252, 252, 253;--tblr-gray-300: #b8c4d4;--tblr-gray-300-rgb: 184, 196, 212;--tblr-gray-300-fg: var(--tblr-light);--tblr-gray-300-darken: #a6b0bf;--tblr-gray-300-lt: #f8f9fb;--tblr-gray-300-lt-rgb: 248, 249, 251;--tblr-gray-400: #8a97ab;--tblr-gray-400-rgb: 138, 151, 171;--tblr-gray-400-fg: var(--tblr-light);--tblr-gray-400-darken: #7c889a;--tblr-gray-400-lt: #f3f5f7;--tblr-gray-400-lt-rgb: 243, 245, 247;--tblr-gray-500: #6c7a91;--tblr-gray-500-rgb: 108, 122, 145;--tblr-gray-500-fg: var(--tblr-light);--tblr-gray-500-darken: #616e83;--tblr-gray-500-lt: #f0f2f4;--tblr-gray-500-lt-rgb: 240, 242, 244;--tblr-gray-600: #49566c;--tblr-gray-600-rgb: 73, 86, 108;--tblr-gray-600-fg: var(--tblr-light);--tblr-gray-600-darken: #424d61;--tblr-gray-600-lt: #edeef0;--tblr-gray-600-lt-rgb: 237, 238, 240;--tblr-gray-700: #3a4859;--tblr-gray-700-rgb: 58, 72, 89;--tblr-gray-700-fg: var(--tblr-light);--tblr-gray-700-darken: #344150;--tblr-gray-700-lt: #ebedee;--tblr-gray-700-lt-rgb: 235, 237, 238;--tblr-gray-800: #182433;--tblr-gray-800-rgb: 24, 36, 51;--tblr-gray-800-fg: var(--tblr-light);--tblr-gray-800-darken: #16202e;--tblr-gray-800-lt: #e8e9eb;--tblr-gray-800-lt-rgb: 232, 233, 235;--tblr-gray-900: #040a11;--tblr-gray-900-rgb: 4, 10, 17;--tblr-gray-900-fg: var(--tblr-light);--tblr-gray-900-darken: #04090f;--tblr-gray-900-lt: #e6e7e7;--tblr-gray-900-lt-rgb: 230, 231, 231;--tblr-spacer-0: 0;--tblr-spacer-1: .25rem;--tblr-spacer-2: .5rem;--tblr-spacer-3: 1rem;--tblr-spacer-4: 1.5rem;--tblr-spacer-5: 2rem;--tblr-spacer-6: 3rem;--tblr-spacer-7: 5rem;--tblr-spacer-8: 8rem;--tblr-spacer: 1rem;--tblr-bg-surface: var(--tblr-white);--tblr-bg-surface-secondary: var(--tblr-gray-100);--tblr-bg-surface-tertiary: var(--tblr-gray-50);--tblr-bg-surface-dark: var(--tblr-dark);--tblr-bg-forms: var(--tblr-bg-surface);--tblr-border-color: #dce1e7;--tblr-border-color-translucent: rgba(4, 32, 69, .1);--tblr-border-dark-color: #8a97ab;--tblr-border-dark-color-translucent: rgba(4, 32, 69, .27);--tblr-border-active-color: #aab2bf;--tblr-icon-color: var(--tblr-gray-400);--tblr-active-bg: rgba(var(--tblr-primary-rgb), .04);--tblr-disabled-bg: var(--tblr-bg-surface-secondary);--tblr-disabled-color: var(--tblr-gray-300);--tblr-code-color: var(--tblr-gray-600);--tblr-code-bg: var(--tblr-bg-surface-secondary);--tblr-dark-mode-border-color: #25384f;--tblr-dark-mode-border-color-translucent: rgba(72, 110, 149, .14);--tblr-dark-mode-border-active-color: #2c415d;--tblr-dark-mode-border-dark-color: #1f2e41;--tblr-page-padding: var(--tblr-spacer-3);--tblr-page-padding-y: var(--tblr-spacer-4);--tblr-font-weight-light: 300;--tblr-font-weight-normal: 400;--tblr-font-weight-medium: 500;--tblr-font-weight-bold: 600;--tblr-font-weight-headings: var(--tblr-font-weight-bold);--tblr-font-size-h1: 1.5rem;--tblr-font-size-h2: 1.25rem;--tblr-font-size-h3: 1rem;--tblr-font-size-h4: .875rem;--tblr-font-size-h5: .75rem;--tblr-font-size-h6: .625rem;--tblr-line-height-h1: 2rem;--tblr-line-height-h2: 1.75rem;--tblr-line-height-h3: 1.5rem;--tblr-line-height-h4: 1.25rem;--tblr-line-height-h5: 1rem;--tblr-line-height-h6: 1rem;--tblr-box-shadow: rgba(var(--tblr-body-color-rgb), .04) 0 2px 4px 0;--tblr-box-shadow-border: inset 0 0 0 1px var(--tblr-border-color-translucent);--tblr-box-shadow-transparent: 0 0 0 0 transparent;--tblr-box-shadow-input: 0 1px 1px rgba(var(--tblr-body-color-rgb), .06);--tblr-box-shadow-card: 0 0 4px rgba(var(--tblr-body-color-rgb), .04);--tblr-box-shadow-card-hover: rgba(var(--tblr-body-color-rgb), .16) 0 2px 16px 0;--tblr-box-shadow-dropdown: 0 16px 24px 2px rgba(0, 0, 0, .07), 0 6px 30px 5px rgba(0, 0, 0, .06), 0 8px 10px -5px rgba(0, 0, 0, .1)}@media (max-width: 991.98px){:root,:host,[data-bs-theme=light]{--tblr-page-padding: var(--tblr-spacer-2)}}@keyframes pulse{0%{opacity:1;transform:scale3d(.8,.8,.8)}50%{transform:scaleZ(1);opacity:1}to{opacity:1;transform:scale3d(.8,.8,.8)}}@keyframes tada{0%{transform:scaleZ(1)}10%,5%{transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-5deg)}15%,25%,35%,45%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,5deg)}20%,30%,40%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-5deg)}50%{transform:scaleZ(1)}}@keyframes rotate-360{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes blink{0%{opacity:0}50%{opacity:1}to{opacity:0}}body{letter-spacing:0;touch-action:manipulation;text-rendering:optimizeLegibility;font-feature-settings:"liga" 0;position:relative;min-height:100%;height:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media print{body{background:transparent}}*{scrollbar-color:rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}*::-webkit-scrollbar{width:1rem;height:1rem;transition:background .3s}@media (prefers-reduced-motion: reduce){*::-webkit-scrollbar{transition:none}}*::-webkit-scrollbar-thumb{border-radius:1rem;border:5px solid transparent;box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}*::-webkit-scrollbar-track{background:transparent}*:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.32)}*::-webkit-scrollbar-corner{background:transparent}.layout-fluid .container,.layout-fluid [class^=container-],.layout-fluid [class*=" container-"]{max-width:100%}.layout-boxed{--tblr-theme-boxed-border-radius: 0;--tblr-theme-boxed-width: 1320px}@media (min-width: 768px){.layout-boxed{background:#182433 linear-gradient(to right,rgba(255,255,255,.1),transparent) fixed;padding:1rem;--tblr-theme-boxed-border-radius: 4px}}.layout-boxed .page{margin:0 auto;max-width:var(--tblr-theme-boxed-width);border-radius:var(--tblr-theme-boxed-border-radius);color:var(--tblr-body-color)}@media (min-width: 768px){.layout-boxed .page{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);background:var(--tblr-body-bg)}}.layout-boxed .page>.navbar:first-child{border-top-left-radius:var(--tblr-theme-boxed-border-radius);border-top-right-radius:var(--tblr-theme-boxed-border-radius)}.navbar{--tblr-navbar-bg: var(--tblr-bg-surface);--tblr-navbar-border-width: var(--tblr-border-width);--tblr-navbar-active-border-color: #00857D;--tblr-navbar-active-bg: rgba(0, 0, 0, .06);--tblr-navbar-color: var(--tblr-body-color);--tblr-navbar-border-color: var(--tblr-border-color);align-items:stretch;min-height:3.5rem;box-shadow:inset 0 calc(-1 * var(--tblr-navbar-border-width)) 0 0 var(--tblr-navbar-border-color);background:var(--tblr-navbar-bg);color:var(--tblr-navbar-color)}.navbar-collapse .navbar{flex-grow:1}.navbar.collapsing{min-height:0}.navbar .dropdown-menu{position:absolute;z-index:1030}.navbar .navbar-nav{min-height:3rem}.navbar .navbar-nav .nav-link{position:relative;min-width:2rem;min-height:2rem;justify-content:center;border-radius:var(--tblr-border-radius)}.navbar .navbar-nav .nav-link .badge{position:absolute;top:.375rem;right:.375rem;transform:translate(50%,-50%)}.navbar-nav{margin:0;padding:0}@media (max-width: 575.98px){.navbar-expand-sm .navbar-collapse{flex-direction:column}.navbar-expand-sm .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-sm .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-sm .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-sm .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-sm .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-sm .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-sm .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 576px){.navbar-expand-sm .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-sm .nav-item.active{position:relative}.navbar-expand-sm .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-sm.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-sm.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-sm.navbar-vertical~.navbar,.navbar-expand-sm.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-sm.navbar-vertical.navbar-right~.navbar,.navbar-expand-sm.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 767.98px){.navbar-expand-md .navbar-collapse{flex-direction:column}.navbar-expand-md .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-md .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-md .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-md .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-md .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-md .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-md .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 768px){.navbar-expand-md .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-md .nav-item.active{position:relative}.navbar-expand-md .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-md.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-md.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-md.navbar-vertical~.navbar,.navbar-expand-md.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-md.navbar-vertical.navbar-right~.navbar,.navbar-expand-md.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 991.98px){.navbar-expand-lg .navbar-collapse{flex-direction:column}.navbar-expand-lg .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-lg .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-lg .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-lg .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-lg .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-lg .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-lg .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 992px){.navbar-expand-lg .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-lg .nav-item.active{position:relative}.navbar-expand-lg .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-lg.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-lg.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-lg.navbar-vertical~.navbar,.navbar-expand-lg.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-lg.navbar-vertical.navbar-right~.navbar,.navbar-expand-lg.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 1199.98px){.navbar-expand-xl .navbar-collapse{flex-direction:column}.navbar-expand-xl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-xl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-xl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-xl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-xl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-xl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-xl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1200px){.navbar-expand-xl .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-xl .nav-item.active{position:relative}.navbar-expand-xl .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-xl.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xl.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xl.navbar-vertical~.navbar,.navbar-expand-xl.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-xl.navbar-vertical.navbar-right~.navbar,.navbar-expand-xl.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 1399.98px){.navbar-expand-xxl .navbar-collapse{flex-direction:column}.navbar-expand-xxl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-xxl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-xxl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-xxl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-xxl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-xxl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-xxl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1400px){.navbar-expand-xxl .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-xxl .nav-item.active{position:relative}.navbar-expand-xxl .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-xxl.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xxl.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xxl.navbar-vertical~.navbar,.navbar-expand-xxl.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-xxl.navbar-vertical.navbar-right~.navbar,.navbar-expand-xxl.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}.navbar-expand .navbar-collapse{flex-direction:column}.navbar-expand .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}.navbar-expand .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand .nav-item.active{position:relative}.navbar-expand .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand.navbar-vertical~.navbar,.navbar-expand.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand.navbar-vertical.navbar-right~.navbar,.navbar-expand.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}.navbar-brand{display:inline-flex;align-items:center;font-weight:var(--tblr-font-weight-bold);margin:0;line-height:1;gap:.5rem}.navbar-brand-image{height:2rem;width:auto}.navbar-toggler{border:0;width:2rem;height:2rem;position:relative;display:flex;align-items:center;justify-content:center}.navbar-toggler-icon{height:2px;width:1.25em;background:currentColor;border-radius:10px;transition:top .2s .2s,bottom .2s .2s,transform .2s,opacity 0s .2s;position:relative}@media (prefers-reduced-motion: reduce){.navbar-toggler-icon{transition:none}}.navbar-toggler-icon:before,.navbar-toggler-icon:after{content:"";display:block;height:inherit;width:inherit;border-radius:inherit;background:inherit;position:absolute;left:0;transition:inherit}@media (prefers-reduced-motion: reduce){.navbar-toggler-icon:before,.navbar-toggler-icon:after{transition:none}}.navbar-toggler-icon:before{top:-.45em}.navbar-toggler-icon:after{bottom:-.45em}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon{transform:rotate(45deg);transition:top .3s,bottom .3s,transform .3s .3s,opacity 0s .3s}@media (prefers-reduced-motion: reduce){.navbar-toggler[aria-expanded=true] .navbar-toggler-icon{transition:none}}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon:before{top:0;transform:rotate(-90deg)}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon:after{bottom:0;opacity:0}.navbar-transparent{--tblr-navbar-border-color: transparent !important;background:transparent!important}.navbar-nav{align-items:stretch}.navbar-nav .nav-item{display:flex;flex-direction:column;justify-content:center}.navbar-side{margin:0;display:flex;flex-direction:row;align-items:center;justify-content:space-around}@media (min-width: 576px){.navbar-vertical.navbar-expand-sm{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 576px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-sm{transition:none}}@media (min-width: 576px){.navbar-vertical.navbar-expand-sm.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-sm .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-sm .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-sm .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-sm>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-sm~.page{padding-left:18rem}.navbar-vertical.navbar-expand-sm~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-sm.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-sm .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-sm .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-sm .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 768px){.navbar-vertical.navbar-expand-md{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 768px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-md{transition:none}}@media (min-width: 768px){.navbar-vertical.navbar-expand-md.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-md .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-md .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-md .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-md .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-md>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-md~.page{padding-left:18rem}.navbar-vertical.navbar-expand-md~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-md.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-md .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-md .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-md .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-md .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-md .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 992px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-lg{transition:none}}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-lg .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-lg .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-lg .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-lg>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-lg~.page{padding-left:18rem}.navbar-vertical.navbar-expand-lg~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-lg.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-lg .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-lg .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1200px){.navbar-vertical.navbar-expand-xl{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 1200px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-xl{transition:none}}@media (min-width: 1200px){.navbar-vertical.navbar-expand-xl.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-xl .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-xl .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-xl .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-xl>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-xl~.page{padding-left:18rem}.navbar-vertical.navbar-expand-xl~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-xl.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-xl .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-xl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-xl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1400px){.navbar-vertical.navbar-expand-xxl{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 1400px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-xxl{transition:none}}@media (min-width: 1400px){.navbar-vertical.navbar-expand-xxl.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-xxl .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-xxl .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-xxl .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-xxl>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-xxl~.page{padding-left:18rem}.navbar-vertical.navbar-expand-xxl~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-xxl.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-xxl .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-xxl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-xxl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}.navbar-vertical.navbar-expand{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}@media (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand{transition:none}}.navbar-vertical.navbar-expand.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand~.page{padding-left:18rem}.navbar-vertical.navbar-expand~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-gray-300);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}.navbar-overlap:after{content:"";height:9rem;position:absolute;top:100%;left:0;right:0;background:inherit;z-index:-1;box-shadow:inherit}.page{display:flex;flex-direction:column;position:relative;min-height:100%}.page-center{justify-content:center}.page-wrapper{flex:1;display:flex;flex-direction:column}@media print{.page-wrapper{margin:0!important}}.page-wrapper-full .page-body:first-child{margin:0;border-top:0}.page-body{margin-top:var(--tblr-page-padding-y);margin-bottom:var(--tblr-page-padding-y);display:flex;flex-direction:column;flex:1}.page-body-card{background:var(--tblr-bg-surface);border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);padding:var(--tblr-page-padding) 0;margin-bottom:0;flex:1}.page-body~.page-body-card{margin-top:0}.page-cover{background:no-repeat center/cover;min-height:9rem}@media (min-width: 768px){.page-cover{min-height:12rem}}@media (min-width: 992px){.page-cover{min-height:15rem}}.page-cover-overlay{position:relative}.page-cover-overlay:after{content:"";position:absolute;inset:0;background-image:linear-gradient(180deg,#0000,#0009)}.page-header{display:flex;flex-wrap:wrap;min-height:2.25rem;flex-direction:column;justify-content:center}.page-wrapper .page-header{margin:var(--tblr-page-padding-y) 0 0}.page-header-border{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);padding:var(--tblr-page-padding-y) 0;margin:0!important;background-color:var(--tblr-bg-surface)}.page-pretitle{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary)}.page-title{margin:0;font-size:var(--tblr-font-size-h2);line-height:var(--tblr-line-height-h2);font-weight:var(--tblr-font-weight-headings);color:inherit;display:flex;align-items:center}.page-title svg{width:1.5rem;height:1.5rem;margin-right:.25rem}.page-title-lg{font-size:1.5rem;line-height:2rem}.page-subtitle{margin-top:.25rem;color:var(--tblr-secondary)}.page-cover{--tblr-page-cover-blur: 20px;--tblr-page-cover-padding: 1rem;min-height:6rem;padding:var(--tblr-page-cover-padding) 0;position:relative;overflow:hidden}.page-cover-img{position:absolute;top:calc(-2 * var(--tblr-page-cover-blur, 0));left:calc(-2 * var(--tblr-page-cover-blur, 0));right:calc(-2 * var(--tblr-page-cover-blur, 0));bottom:calc(-2 * var(--tblr-page-cover-blur, 0));pointer-events:none;filter:blur(var(--tblr-page-cover-blur));object-fit:cover;background-size:cover;background-position:center;z-index:-1}.page-tabs{margin-top:.5rem;position:relative}.page-header-tabs .nav-bordered{border:0}.page-header-tabs+.page-body-card{margin-top:0}.footer{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);background-color:#fff;padding:2rem 0;color:var(--tblr-gray-500);margin-top:auto}.footer-transparent{background-color:transparent;border-top:0}body:not(.theme-dark):not([data-bs-theme=dark]) .hide-theme-light{display:none!important}body:not(.theme-dark):not([data-bs-theme=dark]) .img-dark{display:none!important}body.theme-dark .hide-theme-dark,body[data-bs-theme=dark] .hide-theme-dark,body.theme-dark .img-light,body[data-bs-theme=dark] .img-light{display:none!important}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-body-color: #dce1e7;--tblr-body-color-rgb: 220, 225, 231;--tblr-muted: #49566c;--tblr-body-bg: #151f2c;--tblr-body-bg-rgb: 21, 31, 44;--tblr-emphasis-color: #ffffff;--tblr-emphasis-color-rgb: 255, 255, 255;--tblr-bg-forms: #151f2c;--tblr-bg-surface: #182433;--tblr-bg-surface-dark: #151f2c;--tblr-bg-surface-secondary: #1b293a;--tblr-bg-surface-tertiary: #151f2c;--tblr-link-color: #00aea3;--tblr-link-hover-color: #00857D;--tblr-active-bg: #1b293a;--tblr-disabled-color: var(--tblr-gray-700);--tblr-border-color: var(--tblr-dark-mode-border-color);--tblr-border-color-translucent: var( --tblr-dark-mode-border-color-translucent );--tblr-border-dark-color: var(--tblr-dark-mode-border-dark-color);--tblr-border-active-color: var( --tblr-dark-mode-border-active-color );--tblr-btn-color: #151f2c;--tblr-code-color: var(--tblr-body-color);--tblr-code-bg: #1f2e41;--tblr-primary-lt: #162e3a;--tblr-primary-lt-rgb: 22, 46, 58;--tblr-secondary-lt: #202d3c;--tblr-secondary-lt-rgb: 32, 45, 60;--tblr-success-lt: #1a3235;--tblr-success-lt-rgb: 26, 50, 53;--tblr-info-lt: #1c3044;--tblr-info-lt-rgb: 28, 48, 68;--tblr-warning-lt: #2e2b2f;--tblr-warning-lt-rgb: 46, 43, 47;--tblr-danger-lt: #2b2634;--tblr-danger-lt-rgb: 43, 38, 52;--tblr-light-lt: #2e3947;--tblr-light-lt-rgb: 46, 57, 71;--tblr-dark-lt: #182433;--tblr-dark-lt-rgb: 24, 36, 51;--tblr-muted-lt: #202d3c;--tblr-muted-lt-rgb: 32, 45, 60;--tblr-blue-lt: #162c43;--tblr-blue-lt-rgb: 22, 44, 67;--tblr-azure-lt: #1c3044;--tblr-azure-lt-rgb: 28, 48, 68;--tblr-indigo-lt: #1c2a45;--tblr-indigo-lt-rgb: 28, 42, 69;--tblr-purple-lt: #272742;--tblr-purple-lt-rgb: 39, 39, 66;--tblr-pink-lt: #2b2639;--tblr-pink-lt-rgb: 43, 38, 57;--tblr-red-lt: #2b2634;--tblr-red-lt-rgb: 43, 38, 52;--tblr-orange-lt: #2e2b2f;--tblr-orange-lt-rgb: 46, 43, 47;--tblr-yellow-lt: #2e302e;--tblr-yellow-lt-rgb: 46, 48, 46;--tblr-lime-lt: #213330;--tblr-lime-lt-rgb: 33, 51, 48;--tblr-green-lt: #1a3235;--tblr-green-lt-rgb: 26, 50, 53;--tblr-teal-lt: #17313a;--tblr-teal-lt-rgb: 23, 49, 58;--tblr-cyan-lt: #183140;--tblr-cyan-lt-rgb: 24, 49, 64;--tblr-x-lt: #16202e;--tblr-x-lt-rgb: 22, 32, 46;--tblr-facebook-lt: #182c46;--tblr-facebook-lt-rgb: 24, 44, 70;--tblr-twitter-lt: #193146;--tblr-twitter-lt-rgb: 25, 49, 70;--tblr-linkedin-lt: #172b41;--tblr-linkedin-lt-rgb: 23, 43, 65;--tblr-google-lt: #2c2834;--tblr-google-lt-rgb: 44, 40, 52;--tblr-youtube-lt: #2f202e;--tblr-youtube-lt-rgb: 47, 32, 46;--tblr-vimeo-lt: #183345;--tblr-vimeo-lt-rgb: 24, 51, 69;--tblr-dribbble-lt: #2d283c;--tblr-dribbble-lt-rgb: 45, 40, 60;--tblr-github-lt: #182330;--tblr-github-lt-rgb: 24, 35, 48;--tblr-instagram-lt: #2c2737;--tblr-instagram-lt-rgb: 44, 39, 55;--tblr-pinterest-lt: #292131;--tblr-pinterest-lt-rgb: 41, 33, 49;--tblr-vk-lt: #202e3f;--tblr-vk-lt-rgb: 32, 46, 63;--tblr-rss-lt: #2f312e;--tblr-rss-lt-rgb: 47, 49, 46;--tblr-flickr-lt: #162a44;--tblr-flickr-lt-rgb: 22, 42, 68;--tblr-bitbucket-lt: #162942;--tblr-bitbucket-lt-rgb: 22, 41, 66;--tblr-tabler-lt: #162c43;--tblr-tabler-lt-rgb: 22, 44, 67}[data-bs-theme=dark] .navbar-brand-autodark .navbar-brand-image{filter:brightness(0) invert(1)}.accordion{--tblr-accordion-color: var(--tblr-body-color)}.accordion-button:focus:not(:focus-visible){outline:none;box-shadow:none}.accordion-button:after{opacity:.7}.accordion-button:not(.collapsed){font-weight:var(--tblr-font-weight-bold);border-bottom-color:transparent;box-shadow:none}.accordion-button:not(.collapsed):after{opacity:1}.alert{--tblr-alert-color: var(--tblr-secondary);--tblr-alert-bg: var(--tblr-bg-surface);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-left:.25rem var(--tblr-border-style) var(--tblr-alert-color);box-shadow:#1824330a 0 2px 4px}.alert>:last-child{margin-bottom:0}.alert-important{border-color:transparent;background:var(--tblr-alert-color);color:#fff}.alert-important .alert-icon,.alert-important .alert-link,.alert-important .alert-title,.alert-important .alert-link:hover{color:inherit}.alert-important .btn-close{filter:var(--tblr-btn-close-white-filter)}.alert-link,.alert-link:hover{color:var(--tblr-alert-color)}.alert-primary{--tblr-alert-color: var(--tblr-primary)}.alert-secondary{--tblr-alert-color: var(--tblr-secondary)}.alert-success{--tblr-alert-color: var(--tblr-success)}.alert-info{--tblr-alert-color: var(--tblr-info)}.alert-warning{--tblr-alert-color: var(--tblr-warning)}.alert-danger{--tblr-alert-color: var(--tblr-danger)}.alert-light{--tblr-alert-color: var(--tblr-light)}.alert-dark{--tblr-alert-color: var(--tblr-dark)}.alert-muted{--tblr-alert-color: var(--tblr-muted)}.alert-blue{--tblr-alert-color: var(--tblr-blue)}.alert-azure{--tblr-alert-color: var(--tblr-azure)}.alert-indigo{--tblr-alert-color: var(--tblr-indigo)}.alert-purple{--tblr-alert-color: var(--tblr-purple)}.alert-pink{--tblr-alert-color: var(--tblr-pink)}.alert-red{--tblr-alert-color: var(--tblr-red)}.alert-orange{--tblr-alert-color: var(--tblr-orange)}.alert-yellow{--tblr-alert-color: var(--tblr-yellow)}.alert-lime{--tblr-alert-color: var(--tblr-lime)}.alert-green{--tblr-alert-color: var(--tblr-green)}.alert-teal{--tblr-alert-color: var(--tblr-teal)}.alert-cyan{--tblr-alert-color: var(--tblr-cyan)}.alert-x{--tblr-alert-color: var(--tblr-x)}.alert-facebook{--tblr-alert-color: var(--tblr-facebook)}.alert-twitter{--tblr-alert-color: var(--tblr-twitter)}.alert-linkedin{--tblr-alert-color: var(--tblr-linkedin)}.alert-google{--tblr-alert-color: var(--tblr-google)}.alert-youtube{--tblr-alert-color: var(--tblr-youtube)}.alert-vimeo{--tblr-alert-color: var(--tblr-vimeo)}.alert-dribbble{--tblr-alert-color: var(--tblr-dribbble)}.alert-github{--tblr-alert-color: var(--tblr-github)}.alert-instagram{--tblr-alert-color: var(--tblr-instagram)}.alert-pinterest{--tblr-alert-color: var(--tblr-pinterest)}.alert-vk{--tblr-alert-color: var(--tblr-vk)}.alert-rss{--tblr-alert-color: var(--tblr-rss)}.alert-flickr{--tblr-alert-color: var(--tblr-flickr)}.alert-bitbucket{--tblr-alert-color: var(--tblr-bitbucket)}.alert-tabler{--tblr-alert-color: var(--tblr-tabler)}.alert-icon{color:var(--tblr-alert-color);width:1.5rem!important;height:1.5rem!important;margin:-.125rem 1rem -.125rem 0}.alert-title{font-size:.875rem;line-height:1.25rem;font-weight:var(--tblr-font-weight-bold);margin-bottom:.25rem;color:var(--tblr-alert-color)}.avatar{--tblr-avatar-size: 2.5rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-bg: var(--tblr-bg-surface-secondary);--tblr-avatar-box-shadow: var(--tblr-box-shadow-border);--tblr-avatar-font-size: 1rem;--tblr-avatar-icon-size: 1.5rem;position:relative;width:var(--tblr-avatar-size);height:var(--tblr-avatar-size);font-size:var(--tblr-avatar-font-size);font-weight:var(--tblr-font-weight-medium);line-height:1;display:inline-flex;align-items:center;justify-content:center;color:var(--tblr-secondary);text-align:center;text-transform:uppercase;vertical-align:bottom;user-select:none;background:var(--tblr-avatar-bg) no-repeat center/cover;border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-avatar-box-shadow)}.avatar .icon{width:var(--tblr-avatar-icon-size);height:var(--tblr-avatar-icon-size)}.avatar .badge{position:absolute;right:0;bottom:0;border-radius:100rem;box-shadow:0 0 0 calc(var(--tblr-avatar-status-size) / 4) var(--tblr-bg-surface)}a.avatar{cursor:pointer}.avatar-rounded{border-radius:100rem}.avatar-xxs{--tblr-avatar-size: 1rem;--tblr-avatar-status-size: .25rem;--tblr-avatar-font-size: .5rem;--tblr-avatar-icon-size: .75rem}.avatar-xxs .badge:empty{width:.25rem;height:.25rem}.avatar-xs{--tblr-avatar-size: 1.25rem;--tblr-avatar-status-size: .375rem;--tblr-avatar-font-size: .625rem;--tblr-avatar-icon-size: 1rem}.avatar-xs .badge:empty{width:.375rem;height:.375rem}.avatar-sm{--tblr-avatar-size: 2rem;--tblr-avatar-status-size: .5rem;--tblr-avatar-font-size: .75rem;--tblr-avatar-icon-size: 1.25rem}.avatar-sm .badge:empty{width:.5rem;height:.5rem}.avatar-md{--tblr-avatar-size: 2.5rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-font-size: .875rem;--tblr-avatar-icon-size: 1.5rem}.avatar-md .badge:empty{width:.75rem;height:.75rem}.avatar-lg{--tblr-avatar-size: 3rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-font-size: 1.25rem;--tblr-avatar-icon-size: 2rem}.avatar-lg .badge:empty{width:.75rem;height:.75rem}.avatar-xl{--tblr-avatar-size: 5rem;--tblr-avatar-status-size: 1rem;--tblr-avatar-font-size: 2rem;--tblr-avatar-icon-size: 3rem}.avatar-xl .badge:empty{width:1rem;height:1rem}.avatar-2xl{--tblr-avatar-size: 7rem;--tblr-avatar-status-size: 1rem;--tblr-avatar-font-size: 3rem;--tblr-avatar-icon-size: 5rem}.avatar-2xl .badge:empty{width:1rem;height:1rem}.avatar-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.avatar-list a.avatar:hover{z-index:1}.avatar-list-stacked{display:block;--tblr-list-gap: 0}.avatar-list-stacked .avatar{margin-right:calc(-.5 * var(--tblr-avatar-size))!important;box-shadow:var(--tblr-avatar-box-shadow),0 0 0 2px var(--tblr-card-cap-bg, var(--tblr-card-bg, var(--tblr-bg-surface)))}.avatar-upload{width:4rem;height:4rem;border:var(--tblr-border-width) dashed var(--tblr-border-color);background:var(--tblr-bg-forms);flex-direction:column;transition:color .3s,background-color .3s}@media (prefers-reduced-motion: reduce){.avatar-upload{transition:none}}.avatar-upload svg{width:1.5rem;height:1.5rem;stroke-width:1}.avatar-upload:hover{border-color:var(--tblr-primary);color:var(--tblr-primary);text-decoration:none}.avatar-upload-text{font-size:.625rem;line-height:1;margin-top:.25rem}.avatar-cover{margin-top:calc(-.5 * var(--tblr-avatar-size));box-shadow:0 0 0 .25rem var(--tblr-card-bg, var(--tblr-body-bg))}.badge{justify-content:center;align-items:center;background:var(--tblr-bg-surface-secondary);overflow:hidden;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) transparent;min-width:1.35714285em;font-weight:var(--tblr-font-weight-bold);letter-spacing:.04em;vertical-align:bottom}a.badge{color:var(--tblr-bg-surface)}.badge .avatar{box-sizing:content-box;width:1.25rem;height:1.25rem;margin:0 .5rem 0 -.5rem}.badge .icon{width:1em;height:1em;font-size:1rem;stroke-width:2}.badge:empty,.badge-empty{display:inline-block;width:.5rem;height:.5rem;min-width:0;min-height:auto;padding:0;border-radius:100rem;vertical-align:baseline}.badge-outline{background-color:transparent;border:var(--tblr-border-width) var(--tblr-border-style) currentColor}.badge-pill{border-radius:100rem}.badges-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.badge-notification{position:absolute!important;top:0!important;right:0!important;transform:translate(50%,-50%);z-index:1}.badge-blink{animation:blink 2s infinite}.breadcrumb{--tblr-breadcrumb-item-active-font-weight: var(--tblr-font-weight-bold);--tblr-breadcrumb-item-disabled-color: var(--tblr-disabled-color);--tblr-breadcrumb-link-color: var(--tblr-link-color);padding:0;margin:0;background:transparent}.breadcrumb a{color:var(--tblr-breadcrumb-link-color)}.breadcrumb a:hover{text-decoration:underline}.breadcrumb-muted{--tblr-breadcrumb-link-color: var(--tblr-secondary)}.breadcrumb-item.active{font-weight:var(--tblr-breadcrumb-item-active-font-weight)}.breadcrumb-item.active a{color:inherit;pointer-events:none}.breadcrumb-item.disabled{color:var(--tblr-breadcrumb-item-disabled-color)}.breadcrumb-item.disabled:before{color:inherit}.breadcrumb-item.disabled a{color:inherit;pointer-events:none}.breadcrumb-dots{--tblr-breadcrumb-divider: "\b7"}.breadcrumb-arrows{--tblr-breadcrumb-divider: "\203a"}.breadcrumb-bullets{--tblr-breadcrumb-divider: "\2022"}.btn{--tblr-btn-icon-size: 1.25rem;--tblr-btn-bg: var(--tblr-bg-surface);--tblr-btn-color: var(--tblr-body-color);--tblr-btn-border-color: var(--tblr-border-color);--tblr-btn-hover-bg: var(--tblr-btn-bg);--tblr-btn-hover-border-color: var(--tblr-border-active-color);--tblr-btn-box-shadow: var(--tblr-box-shadow-input);--tblr-btn-active-color: var(--tblr-primary);--tblr-btn-active-bg: rgba(var(--tblr-primary-rgb), .04);--tblr-btn-active-border-color: var(--tblr-primary);display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;box-shadow:var(--tblr-btn-box-shadow)}.btn .icon{width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);min-width:var(--tblr-btn-icon-size);margin:0 calc(var(--tblr-btn-padding-x) / 2) 0 calc(var(--tblr-btn-padding-x) / -4);vertical-align:bottom;color:inherit}.btn .avatar{width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);margin:0 calc(var(--tblr-btn-padding-x) / 2) 0 calc(var(--tblr-btn-padding-x) / -4)}.btn .icon-right{margin:0 calc(var(--tblr-btn-padding-x) / -4) 0 calc(var(--tblr-btn-padding-x) / 2)}.btn .badge{top:auto}.btn-check+.btn:hover{color:var(--tblr-btn-hover-color);background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color)}.btn-link{color:#009f95;background-color:transparent;border-color:transparent;box-shadow:none}.btn-link .icon{color:inherit}.btn-link:hover{color:#006a64;border-color:transparent}.btn-primary{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-primary-fg);--tblr-btn-bg: var(--tblr-primary);--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-bg: rgba(var(--tblr-primary-rgb), .8);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: rgba(var(--tblr-primary-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-primary);--tblr-btn-disabled-color: var(--tblr-primary-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-primary{--tblr-btn-color: var(--tblr-primary);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-primary);--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-primary);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: var(--tblr-primary);--tblr-btn-disabled-color: var(--tblr-primary);--tblr-btn-disabled-border-color: var(--tblr-primary)}.btn-secondary{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-secondary-fg);--tblr-btn-bg: var(--tblr-secondary);--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-bg: rgba(var(--tblr-secondary-rgb), .8);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: rgba(var(--tblr-secondary-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-secondary);--tblr-btn-disabled-color: var(--tblr-secondary-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-secondary{--tblr-btn-color: var(--tblr-secondary);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-secondary);--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-secondary);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: var(--tblr-secondary);--tblr-btn-disabled-color: var(--tblr-secondary);--tblr-btn-disabled-border-color: var(--tblr-secondary)}.btn-success{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-success-fg);--tblr-btn-bg: var(--tblr-success);--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-bg: rgba(var(--tblr-success-rgb), .8);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: rgba(var(--tblr-success-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-success);--tblr-btn-disabled-color: var(--tblr-success-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-success{--tblr-btn-color: var(--tblr-success);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-success);--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-success);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: var(--tblr-success);--tblr-btn-disabled-color: var(--tblr-success);--tblr-btn-disabled-border-color: var(--tblr-success)}.btn-info{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-info-fg);--tblr-btn-bg: var(--tblr-info);--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-bg: rgba(var(--tblr-info-rgb), .8);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: rgba(var(--tblr-info-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-info);--tblr-btn-disabled-color: var(--tblr-info-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-info{--tblr-btn-color: var(--tblr-info);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-info);--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-info);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: var(--tblr-info);--tblr-btn-disabled-color: var(--tblr-info);--tblr-btn-disabled-border-color: var(--tblr-info)}.btn-warning{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-warning-fg);--tblr-btn-bg: var(--tblr-warning);--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-bg: rgba(var(--tblr-warning-rgb), .8);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: rgba(var(--tblr-warning-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-warning);--tblr-btn-disabled-color: var(--tblr-warning-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-warning{--tblr-btn-color: var(--tblr-warning);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-warning);--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-warning);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: var(--tblr-warning);--tblr-btn-disabled-color: var(--tblr-warning);--tblr-btn-disabled-border-color: var(--tblr-warning)}.btn-danger{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-danger-fg);--tblr-btn-bg: var(--tblr-danger);--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-bg: rgba(var(--tblr-danger-rgb), .8);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: rgba(var(--tblr-danger-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-danger);--tblr-btn-disabled-color: var(--tblr-danger-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-danger{--tblr-btn-color: var(--tblr-danger);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-danger);--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-danger);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: var(--tblr-danger);--tblr-btn-disabled-color: var(--tblr-danger);--tblr-btn-disabled-border-color: var(--tblr-danger)}.btn-light{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-light-fg);--tblr-btn-bg: var(--tblr-light);--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-bg: rgba(var(--tblr-light-rgb), .8);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: rgba(var(--tblr-light-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-light);--tblr-btn-disabled-color: var(--tblr-light-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-light{--tblr-btn-color: var(--tblr-light);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-light);--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-light);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: var(--tblr-light);--tblr-btn-disabled-color: var(--tblr-light);--tblr-btn-disabled-border-color: var(--tblr-light)}.btn-dark{--tblr-btn-border-color: var(--tblr-dark-mode-border-color);--tblr-btn-hover-border-color: var(--tblr-dark-mode-border-active-color);--tblr-btn-active-border-color: var(--tblr-dark-mode-border-active-color);--tblr-btn-color: var(--tblr-dark-fg);--tblr-btn-bg: var(--tblr-dark);--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-bg: rgba(var(--tblr-dark-rgb), .8);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: rgba(var(--tblr-dark-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-dark);--tblr-btn-disabled-color: var(--tblr-dark-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-dark{--tblr-btn-color: var(--tblr-dark);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-dark);--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-dark);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: var(--tblr-dark);--tblr-btn-disabled-color: var(--tblr-dark);--tblr-btn-disabled-border-color: var(--tblr-dark)}.btn-muted{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-muted-fg);--tblr-btn-bg: var(--tblr-muted);--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-bg: rgba(var(--tblr-muted-rgb), .8);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: rgba(var(--tblr-muted-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-muted);--tblr-btn-disabled-color: var(--tblr-muted-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-muted{--tblr-btn-color: var(--tblr-muted);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-muted);--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-muted);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: var(--tblr-muted);--tblr-btn-disabled-color: var(--tblr-muted);--tblr-btn-disabled-border-color: var(--tblr-muted)}.btn-blue{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-blue-fg);--tblr-btn-bg: var(--tblr-blue);--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-bg: rgba(var(--tblr-blue-rgb), .8);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: rgba(var(--tblr-blue-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-blue);--tblr-btn-disabled-color: var(--tblr-blue-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-blue{--tblr-btn-color: var(--tblr-blue);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-blue);--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-blue);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: var(--tblr-blue);--tblr-btn-disabled-color: var(--tblr-blue);--tblr-btn-disabled-border-color: var(--tblr-blue)}.btn-azure{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-azure-fg);--tblr-btn-bg: var(--tblr-azure);--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-bg: rgba(var(--tblr-azure-rgb), .8);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: rgba(var(--tblr-azure-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-azure);--tblr-btn-disabled-color: var(--tblr-azure-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-azure{--tblr-btn-color: var(--tblr-azure);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-azure);--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-azure);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: var(--tblr-azure);--tblr-btn-disabled-color: var(--tblr-azure);--tblr-btn-disabled-border-color: var(--tblr-azure)}.btn-indigo{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-indigo-fg);--tblr-btn-bg: var(--tblr-indigo);--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-bg: rgba(var(--tblr-indigo-rgb), .8);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: rgba(var(--tblr-indigo-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-indigo);--tblr-btn-disabled-color: var(--tblr-indigo-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-indigo{--tblr-btn-color: var(--tblr-indigo);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-indigo);--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-indigo);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: var(--tblr-indigo);--tblr-btn-disabled-color: var(--tblr-indigo);--tblr-btn-disabled-border-color: var(--tblr-indigo)}.btn-purple{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-purple-fg);--tblr-btn-bg: var(--tblr-purple);--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-bg: rgba(var(--tblr-purple-rgb), .8);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: rgba(var(--tblr-purple-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-purple);--tblr-btn-disabled-color: var(--tblr-purple-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-purple{--tblr-btn-color: var(--tblr-purple);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-purple);--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-purple);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: var(--tblr-purple);--tblr-btn-disabled-color: var(--tblr-purple);--tblr-btn-disabled-border-color: var(--tblr-purple)}.btn-pink{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-pink-fg);--tblr-btn-bg: var(--tblr-pink);--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-bg: rgba(var(--tblr-pink-rgb), .8);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: rgba(var(--tblr-pink-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-pink);--tblr-btn-disabled-color: var(--tblr-pink-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-pink{--tblr-btn-color: var(--tblr-pink);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-pink);--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-pink);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: var(--tblr-pink);--tblr-btn-disabled-color: var(--tblr-pink);--tblr-btn-disabled-border-color: var(--tblr-pink)}.btn-red{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-red-fg);--tblr-btn-bg: var(--tblr-red);--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-bg: rgba(var(--tblr-red-rgb), .8);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: rgba(var(--tblr-red-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-red);--tblr-btn-disabled-color: var(--tblr-red-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-red{--tblr-btn-color: var(--tblr-red);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-red);--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-red);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: var(--tblr-red);--tblr-btn-disabled-color: var(--tblr-red);--tblr-btn-disabled-border-color: var(--tblr-red)}.btn-orange{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-orange-fg);--tblr-btn-bg: var(--tblr-orange);--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-bg: rgba(var(--tblr-orange-rgb), .8);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: rgba(var(--tblr-orange-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-orange);--tblr-btn-disabled-color: var(--tblr-orange-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-orange{--tblr-btn-color: var(--tblr-orange);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-orange);--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-orange);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: var(--tblr-orange);--tblr-btn-disabled-color: var(--tblr-orange);--tblr-btn-disabled-border-color: var(--tblr-orange)}.btn-yellow{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-yellow-fg);--tblr-btn-bg: var(--tblr-yellow);--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-bg: rgba(var(--tblr-yellow-rgb), .8);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: rgba(var(--tblr-yellow-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-yellow);--tblr-btn-disabled-color: var(--tblr-yellow-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-yellow{--tblr-btn-color: var(--tblr-yellow);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-yellow);--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-yellow);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: var(--tblr-yellow);--tblr-btn-disabled-color: var(--tblr-yellow);--tblr-btn-disabled-border-color: var(--tblr-yellow)}.btn-lime{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-lime-fg);--tblr-btn-bg: var(--tblr-lime);--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-bg: rgba(var(--tblr-lime-rgb), .8);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: rgba(var(--tblr-lime-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-lime);--tblr-btn-disabled-color: var(--tblr-lime-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-lime{--tblr-btn-color: var(--tblr-lime);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-lime);--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-lime);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: var(--tblr-lime);--tblr-btn-disabled-color: var(--tblr-lime);--tblr-btn-disabled-border-color: var(--tblr-lime)}.btn-green{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-green-fg);--tblr-btn-bg: var(--tblr-green);--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-bg: rgba(var(--tblr-green-rgb), .8);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: rgba(var(--tblr-green-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-green);--tblr-btn-disabled-color: var(--tblr-green-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-green{--tblr-btn-color: var(--tblr-green);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-green);--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-green);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: var(--tblr-green);--tblr-btn-disabled-color: var(--tblr-green);--tblr-btn-disabled-border-color: var(--tblr-green)}.btn-teal{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-teal-fg);--tblr-btn-bg: var(--tblr-teal);--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-bg: rgba(var(--tblr-teal-rgb), .8);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: rgba(var(--tblr-teal-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-teal);--tblr-btn-disabled-color: var(--tblr-teal-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-teal{--tblr-btn-color: var(--tblr-teal);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-teal);--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-teal);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: var(--tblr-teal);--tblr-btn-disabled-color: var(--tblr-teal);--tblr-btn-disabled-border-color: var(--tblr-teal)}.btn-cyan{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-cyan-fg);--tblr-btn-bg: var(--tblr-cyan);--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-bg: rgba(var(--tblr-cyan-rgb), .8);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: rgba(var(--tblr-cyan-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-cyan);--tblr-btn-disabled-color: var(--tblr-cyan-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-cyan{--tblr-btn-color: var(--tblr-cyan);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-cyan);--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-cyan);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: var(--tblr-cyan);--tblr-btn-disabled-color: var(--tblr-cyan);--tblr-btn-disabled-border-color: var(--tblr-cyan)}.btn-x{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-x-fg);--tblr-btn-bg: var(--tblr-x);--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-bg: rgba(var(--tblr-x-rgb), .8);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: rgba(var(--tblr-x-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-x);--tblr-btn-disabled-color: var(--tblr-x-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-x{--tblr-btn-color: var(--tblr-x);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-x);--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-x);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: var(--tblr-x);--tblr-btn-disabled-color: var(--tblr-x);--tblr-btn-disabled-border-color: var(--tblr-x)}.btn-facebook{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-facebook-fg);--tblr-btn-bg: var(--tblr-facebook);--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-bg: rgba(var(--tblr-facebook-rgb), .8);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: rgba(var(--tblr-facebook-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-facebook);--tblr-btn-disabled-color: var(--tblr-facebook-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-facebook{--tblr-btn-color: var(--tblr-facebook);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-facebook);--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-facebook);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: var(--tblr-facebook);--tblr-btn-disabled-color: var(--tblr-facebook);--tblr-btn-disabled-border-color: var(--tblr-facebook)}.btn-twitter{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-twitter-fg);--tblr-btn-bg: var(--tblr-twitter);--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-bg: rgba(var(--tblr-twitter-rgb), .8);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: rgba(var(--tblr-twitter-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-twitter);--tblr-btn-disabled-color: var(--tblr-twitter-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-twitter{--tblr-btn-color: var(--tblr-twitter);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-twitter);--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-twitter);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: var(--tblr-twitter);--tblr-btn-disabled-color: var(--tblr-twitter);--tblr-btn-disabled-border-color: var(--tblr-twitter)}.btn-linkedin{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-linkedin-fg);--tblr-btn-bg: var(--tblr-linkedin);--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-bg: rgba(var(--tblr-linkedin-rgb), .8);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: rgba(var(--tblr-linkedin-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-linkedin);--tblr-btn-disabled-color: var(--tblr-linkedin-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-linkedin{--tblr-btn-color: var(--tblr-linkedin);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-linkedin);--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-linkedin);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: var(--tblr-linkedin);--tblr-btn-disabled-color: var(--tblr-linkedin);--tblr-btn-disabled-border-color: var(--tblr-linkedin)}.btn-google{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-google-fg);--tblr-btn-bg: var(--tblr-google);--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-bg: rgba(var(--tblr-google-rgb), .8);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: rgba(var(--tblr-google-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-google);--tblr-btn-disabled-color: var(--tblr-google-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-google{--tblr-btn-color: var(--tblr-google);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-google);--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-google);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: var(--tblr-google);--tblr-btn-disabled-color: var(--tblr-google);--tblr-btn-disabled-border-color: var(--tblr-google)}.btn-youtube{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-youtube-fg);--tblr-btn-bg: var(--tblr-youtube);--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-bg: rgba(var(--tblr-youtube-rgb), .8);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: rgba(var(--tblr-youtube-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-youtube);--tblr-btn-disabled-color: var(--tblr-youtube-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-youtube{--tblr-btn-color: var(--tblr-youtube);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-youtube);--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-youtube);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: var(--tblr-youtube);--tblr-btn-disabled-color: var(--tblr-youtube);--tblr-btn-disabled-border-color: var(--tblr-youtube)}.btn-vimeo{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-vimeo-fg);--tblr-btn-bg: var(--tblr-vimeo);--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-bg: rgba(var(--tblr-vimeo-rgb), .8);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: rgba(var(--tblr-vimeo-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-vimeo);--tblr-btn-disabled-color: var(--tblr-vimeo-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-vimeo{--tblr-btn-color: var(--tblr-vimeo);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-vimeo);--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-vimeo);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: var(--tblr-vimeo);--tblr-btn-disabled-color: var(--tblr-vimeo);--tblr-btn-disabled-border-color: var(--tblr-vimeo)}.btn-dribbble{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-dribbble-fg);--tblr-btn-bg: var(--tblr-dribbble);--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-bg: rgba(var(--tblr-dribbble-rgb), .8);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: rgba(var(--tblr-dribbble-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-dribbble);--tblr-btn-disabled-color: var(--tblr-dribbble-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-dribbble{--tblr-btn-color: var(--tblr-dribbble);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-dribbble);--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-dribbble);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: var(--tblr-dribbble);--tblr-btn-disabled-color: var(--tblr-dribbble);--tblr-btn-disabled-border-color: var(--tblr-dribbble)}.btn-github{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-github-fg);--tblr-btn-bg: var(--tblr-github);--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-bg: rgba(var(--tblr-github-rgb), .8);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: rgba(var(--tblr-github-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-github);--tblr-btn-disabled-color: var(--tblr-github-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-github{--tblr-btn-color: var(--tblr-github);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-github);--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-github);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: var(--tblr-github);--tblr-btn-disabled-color: var(--tblr-github);--tblr-btn-disabled-border-color: var(--tblr-github)}.btn-instagram{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-instagram-fg);--tblr-btn-bg: var(--tblr-instagram);--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-bg: rgba(var(--tblr-instagram-rgb), .8);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: rgba(var(--tblr-instagram-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-instagram);--tblr-btn-disabled-color: var(--tblr-instagram-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-instagram{--tblr-btn-color: var(--tblr-instagram);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-instagram);--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-instagram);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: var(--tblr-instagram);--tblr-btn-disabled-color: var(--tblr-instagram);--tblr-btn-disabled-border-color: var(--tblr-instagram)}.btn-pinterest{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-pinterest-fg);--tblr-btn-bg: var(--tblr-pinterest);--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-bg: rgba(var(--tblr-pinterest-rgb), .8);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: rgba(var(--tblr-pinterest-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-pinterest);--tblr-btn-disabled-color: var(--tblr-pinterest-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-pinterest{--tblr-btn-color: var(--tblr-pinterest);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-pinterest);--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-pinterest);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: var(--tblr-pinterest);--tblr-btn-disabled-color: var(--tblr-pinterest);--tblr-btn-disabled-border-color: var(--tblr-pinterest)}.btn-vk{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-vk-fg);--tblr-btn-bg: var(--tblr-vk);--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-bg: rgba(var(--tblr-vk-rgb), .8);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: rgba(var(--tblr-vk-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-vk);--tblr-btn-disabled-color: var(--tblr-vk-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-vk{--tblr-btn-color: var(--tblr-vk);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-vk);--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-vk);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: var(--tblr-vk);--tblr-btn-disabled-color: var(--tblr-vk);--tblr-btn-disabled-border-color: var(--tblr-vk)}.btn-rss{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-rss-fg);--tblr-btn-bg: var(--tblr-rss);--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-bg: rgba(var(--tblr-rss-rgb), .8);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: rgba(var(--tblr-rss-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-rss);--tblr-btn-disabled-color: var(--tblr-rss-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-rss{--tblr-btn-color: var(--tblr-rss);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-rss);--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-rss);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: var(--tblr-rss);--tblr-btn-disabled-color: var(--tblr-rss);--tblr-btn-disabled-border-color: var(--tblr-rss)}.btn-flickr{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-flickr-fg);--tblr-btn-bg: var(--tblr-flickr);--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-bg: rgba(var(--tblr-flickr-rgb), .8);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: rgba(var(--tblr-flickr-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-flickr);--tblr-btn-disabled-color: var(--tblr-flickr-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-flickr{--tblr-btn-color: var(--tblr-flickr);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-flickr);--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-flickr);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: var(--tblr-flickr);--tblr-btn-disabled-color: var(--tblr-flickr);--tblr-btn-disabled-border-color: var(--tblr-flickr)}.btn-bitbucket{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-bitbucket-fg);--tblr-btn-bg: var(--tblr-bitbucket);--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-bg: rgba(var(--tblr-bitbucket-rgb), .8);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: rgba(var(--tblr-bitbucket-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-bitbucket);--tblr-btn-disabled-color: var(--tblr-bitbucket-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-bitbucket{--tblr-btn-color: var(--tblr-bitbucket);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-bitbucket);--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-bitbucket);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: var(--tblr-bitbucket);--tblr-btn-disabled-color: var(--tblr-bitbucket);--tblr-btn-disabled-border-color: var(--tblr-bitbucket)}.btn-tabler{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-tabler-fg);--tblr-btn-bg: var(--tblr-tabler);--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-bg: rgba(var(--tblr-tabler-rgb), .8);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: rgba(var(--tblr-tabler-rgb), .8);--tblr-btn-disabled-bg: var(--tblr-tabler);--tblr-btn-disabled-color: var(--tblr-tabler-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-tabler{--tblr-btn-color: var(--tblr-tabler);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-tabler);--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-tabler);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: var(--tblr-tabler);--tblr-btn-disabled-color: var(--tblr-tabler);--tblr-btn-disabled-border-color: var(--tblr-tabler)}.btn-ghost-primary{--tblr-btn-color: var(--tblr-primary);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-bg: var(--tblr-primary);--tblr-btn-hover-border-color: var(--tblr-primary);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: var(--tblr-primary);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-primary);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-secondary{--tblr-btn-color: var(--tblr-secondary);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-bg: var(--tblr-secondary);--tblr-btn-hover-border-color: var(--tblr-secondary);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: var(--tblr-secondary);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-secondary);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-success{--tblr-btn-color: var(--tblr-success);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-bg: var(--tblr-success);--tblr-btn-hover-border-color: var(--tblr-success);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: var(--tblr-success);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-success);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-info{--tblr-btn-color: var(--tblr-info);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-bg: var(--tblr-info);--tblr-btn-hover-border-color: var(--tblr-info);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: var(--tblr-info);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-info);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-warning{--tblr-btn-color: var(--tblr-warning);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-bg: var(--tblr-warning);--tblr-btn-hover-border-color: var(--tblr-warning);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: var(--tblr-warning);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-warning);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-danger{--tblr-btn-color: var(--tblr-danger);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-bg: var(--tblr-danger);--tblr-btn-hover-border-color: var(--tblr-danger);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: var(--tblr-danger);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-danger);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-light{--tblr-btn-color: var(--tblr-light);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-bg: var(--tblr-light);--tblr-btn-hover-border-color: var(--tblr-light);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: var(--tblr-light);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-light);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-dark{--tblr-btn-color: var(--tblr-dark);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-bg: var(--tblr-dark);--tblr-btn-hover-border-color: var(--tblr-dark);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: var(--tblr-dark);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-dark);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-muted{--tblr-btn-color: var(--tblr-muted);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-bg: var(--tblr-muted);--tblr-btn-hover-border-color: var(--tblr-muted);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: var(--tblr-muted);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-muted);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-blue{--tblr-btn-color: var(--tblr-blue);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-bg: var(--tblr-blue);--tblr-btn-hover-border-color: var(--tblr-blue);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: var(--tblr-blue);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-blue);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-azure{--tblr-btn-color: var(--tblr-azure);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-bg: var(--tblr-azure);--tblr-btn-hover-border-color: var(--tblr-azure);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: var(--tblr-azure);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-azure);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-indigo{--tblr-btn-color: var(--tblr-indigo);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-bg: var(--tblr-indigo);--tblr-btn-hover-border-color: var(--tblr-indigo);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: var(--tblr-indigo);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-indigo);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-purple{--tblr-btn-color: var(--tblr-purple);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-bg: var(--tblr-purple);--tblr-btn-hover-border-color: var(--tblr-purple);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: var(--tblr-purple);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-purple);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-pink{--tblr-btn-color: var(--tblr-pink);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-bg: var(--tblr-pink);--tblr-btn-hover-border-color: var(--tblr-pink);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: var(--tblr-pink);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-pink);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-red{--tblr-btn-color: var(--tblr-red);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-bg: var(--tblr-red);--tblr-btn-hover-border-color: var(--tblr-red);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: var(--tblr-red);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-red);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-orange{--tblr-btn-color: var(--tblr-orange);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-bg: var(--tblr-orange);--tblr-btn-hover-border-color: var(--tblr-orange);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: var(--tblr-orange);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-orange);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-yellow{--tblr-btn-color: var(--tblr-yellow);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-bg: var(--tblr-yellow);--tblr-btn-hover-border-color: var(--tblr-yellow);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: var(--tblr-yellow);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-yellow);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-lime{--tblr-btn-color: var(--tblr-lime);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-bg: var(--tblr-lime);--tblr-btn-hover-border-color: var(--tblr-lime);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: var(--tblr-lime);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-lime);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-green{--tblr-btn-color: var(--tblr-green);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-bg: var(--tblr-green);--tblr-btn-hover-border-color: var(--tblr-green);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: var(--tblr-green);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-green);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-teal{--tblr-btn-color: var(--tblr-teal);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-bg: var(--tblr-teal);--tblr-btn-hover-border-color: var(--tblr-teal);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: var(--tblr-teal);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-teal);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-cyan{--tblr-btn-color: var(--tblr-cyan);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-bg: var(--tblr-cyan);--tblr-btn-hover-border-color: var(--tblr-cyan);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: var(--tblr-cyan);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-cyan);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-x{--tblr-btn-color: var(--tblr-x);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-bg: var(--tblr-x);--tblr-btn-hover-border-color: var(--tblr-x);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: var(--tblr-x);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-x);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-facebook{--tblr-btn-color: var(--tblr-facebook);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-bg: var(--tblr-facebook);--tblr-btn-hover-border-color: var(--tblr-facebook);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: var(--tblr-facebook);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-facebook);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-twitter{--tblr-btn-color: var(--tblr-twitter);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-bg: var(--tblr-twitter);--tblr-btn-hover-border-color: var(--tblr-twitter);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: var(--tblr-twitter);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-twitter);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-linkedin{--tblr-btn-color: var(--tblr-linkedin);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-bg: var(--tblr-linkedin);--tblr-btn-hover-border-color: var(--tblr-linkedin);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: var(--tblr-linkedin);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-linkedin);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-google{--tblr-btn-color: var(--tblr-google);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-bg: var(--tblr-google);--tblr-btn-hover-border-color: var(--tblr-google);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: var(--tblr-google);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-google);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-youtube{--tblr-btn-color: var(--tblr-youtube);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-bg: var(--tblr-youtube);--tblr-btn-hover-border-color: var(--tblr-youtube);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: var(--tblr-youtube);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-youtube);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-vimeo{--tblr-btn-color: var(--tblr-vimeo);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-bg: var(--tblr-vimeo);--tblr-btn-hover-border-color: var(--tblr-vimeo);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: var(--tblr-vimeo);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-vimeo);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-dribbble{--tblr-btn-color: var(--tblr-dribbble);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-bg: var(--tblr-dribbble);--tblr-btn-hover-border-color: var(--tblr-dribbble);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: var(--tblr-dribbble);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-dribbble);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-github{--tblr-btn-color: var(--tblr-github);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-bg: var(--tblr-github);--tblr-btn-hover-border-color: var(--tblr-github);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: var(--tblr-github);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-github);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-instagram{--tblr-btn-color: var(--tblr-instagram);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-bg: var(--tblr-instagram);--tblr-btn-hover-border-color: var(--tblr-instagram);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: var(--tblr-instagram);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-instagram);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-pinterest{--tblr-btn-color: var(--tblr-pinterest);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-bg: var(--tblr-pinterest);--tblr-btn-hover-border-color: var(--tblr-pinterest);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: var(--tblr-pinterest);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-pinterest);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-vk{--tblr-btn-color: var(--tblr-vk);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-bg: var(--tblr-vk);--tblr-btn-hover-border-color: var(--tblr-vk);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: var(--tblr-vk);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-vk);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-rss{--tblr-btn-color: var(--tblr-rss);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-bg: var(--tblr-rss);--tblr-btn-hover-border-color: var(--tblr-rss);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: var(--tblr-rss);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-rss);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-flickr{--tblr-btn-color: var(--tblr-flickr);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-bg: var(--tblr-flickr);--tblr-btn-hover-border-color: var(--tblr-flickr);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: var(--tblr-flickr);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-flickr);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-bitbucket{--tblr-btn-color: var(--tblr-bitbucket);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-bg: var(--tblr-bitbucket);--tblr-btn-hover-border-color: var(--tblr-bitbucket);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: var(--tblr-bitbucket);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-bitbucket);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-tabler{--tblr-btn-color: var(--tblr-tabler);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-bg: var(--tblr-tabler);--tblr-btn-hover-border-color: var(--tblr-tabler);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: var(--tblr-tabler);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-tabler);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-sm,.btn-group-sm>.btn{--tblr-btn-line-height: 1.5;--tblr-btn-icon-size: .75rem}.btn-lg,.btn-group-lg>.btn{--tblr-btn-line-height: 1.5;--tblr-btn-icon-size: 2rem}.btn-pill{padding-right:1.5em;padding-left:1.5em;border-radius:10rem}.btn-pill[class*=btn-icon]{padding:.375rem 15px}.btn-square{border-radius:0}.btn-icon{min-width:calc(var(--tblr-btn-line-height) * var(--tblr-btn-font-size) + var(--tblr-btn-padding-y) * 2 + var(--tblr-btn-border-width) * 2);min-height:calc(var(--tblr-btn-line-height) * var(--tblr-btn-font-size) + var(--tblr-btn-padding-y) * 2 + var(--tblr-btn-border-width) * 2);padding-left:0;padding-right:0}.btn-icon .icon{margin:calc(-1 * var(--tblr-btn-padding-x))}.btn-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.btn-floating{position:fixed;z-index:1030;bottom:1.5rem;right:1.5rem;border-radius:100rem}.btn-loading{position:relative;color:transparent!important;text-shadow:none!important;pointer-events:none}.btn-loading>*{opacity:0}.btn-loading:after{content:"";display:inline-block;vertical-align:text-bottom;border:2px var(--tblr-border-style) currentColor;border-right-color:transparent;border-radius:100rem;color:var(--tblr-btn-color);position:absolute;width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);left:calc(50% - var(--tblr-btn-icon-size) / 2);top:calc(50% - var(--tblr-btn-icon-size) / 2);animation:spinner-border .75s linear infinite}.btn-action{padding:0;border:0;color:var(--tblr-secondary);display:inline-flex;width:2rem;height:2rem;align-items:center;justify-content:center;border-radius:var(--tblr-border-radius);background:transparent}.btn-action:after{content:none}.btn-action:focus{outline:none;box-shadow:none}.btn-action:hover,.btn-action.show{color:var(--tblr-body-color);background:var(--tblr-active-bg)}.btn-action.show{color:var(--tblr-primary)}.btn-action .icon{margin:0;width:1.25rem;height:1.25rem;font-size:1.25rem;stroke-width:1}.btn-actions{display:flex}.btn-group,.btn-group-vertical{box-shadow:var(--tblr-box-shadow-input)}.btn-group>.btn-check:checked+.btn,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:5}.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus{z-index:1}.calendar{display:block;font-size:.765625rem;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.calendar-nav{display:flex;align-items:center}.calendar-title{flex:1;text-align:center}.calendar-body,.calendar-header{display:flex;flex-wrap:wrap;justify-content:flex-start;padding:.5rem 0}.calendar-header{color:var(--tblr-secondary)}.calendar-date{flex:0 0 14.2857142857%;max-width:14.2857142857%;padding:.2rem;text-align:center;border:0}.calendar-date.prev-month,.calendar-date.next-month{opacity:.25}.calendar-date .date-item{position:relative;display:inline-block;width:1.4rem;height:1.4rem;line-height:1.4rem;color:#66758c;text-align:center;text-decoration:none;white-space:nowrap;vertical-align:middle;cursor:pointer;background:0 0;border:var(--tblr-border-width) var(--tblr-border-style) transparent;border-radius:100rem;outline:0;transition:background .3s,border .3s,box-shadow .32s,color .3s}@media (prefers-reduced-motion: reduce){.calendar-date .date-item{transition:none}}.calendar-date .date-item:hover{color:var(--tblr-primary);text-decoration:none;background:#fefeff;border-color:var(--tblr-border-color)}.calendar-date .date-today{color:var(--tblr-primary);border-color:var(--tblr-border-color)}.calendar-range{position:relative}.calendar-range:before{position:absolute;top:50%;right:0;left:0;height:1.4rem;content:"";background:rgba(var(--tblr-primary-rgb),.1);transform:translateY(-50%)}.calendar-range.range-start .date-item,.calendar-range.range-end .date-item{color:#fff;background:var(--tblr-primary);border-color:var(--tblr-primary)}.calendar-range.range-start:before{left:50%}.calendar-range.range-end:before{right:50%}.carousel-indicators-vertical{left:auto;top:0;margin:0 1rem 0 0;flex-direction:column}.carousel-indicators-vertical [data-bs-target]{margin:3px 0;width:3px;height:30px;border:0;border-left:10px var(--tblr-border-style) transparent;border-right:10px var(--tblr-border-style) transparent}.carousel-indicators-dot [data-bs-target]{width:.5rem;height:.5rem;border-radius:100rem;border:10px var(--tblr-border-style) transparent;margin:0}.carousel-indicators-thumb [data-bs-target]{width:2rem;height:auto;background:no-repeat center/cover;border:0;border-radius:var(--tblr-border-radius);box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px;margin:0 3px;opacity:.75}@media (min-width: 992px){.carousel-indicators-thumb [data-bs-target]{width:4rem}}.carousel-indicators-thumb [data-bs-target]:before{content:"";padding-top:var(--tblr-aspect-ratio, 100%);display:block}.carousel-indicators-thumb.carousel-indicators-vertical [data-bs-target]{margin:3px 0}.carousel-caption-background{background:red;position:absolute;left:0;right:0;bottom:0;height:90%;background:linear-gradient(0deg,#182433e6,#18243300)}.card{transition:transform .3s ease-out,opacity .3s ease-out,box-shadow .3s ease-out}@media (prefers-reduced-motion: reduce){.card{transition:none}}@media print{.card{border:none;box-shadow:none}}a.card{color:inherit}a.card:hover{text-decoration:none;box-shadow:rgba(var(--tblr-body-color-rgb),.16) 0 2px 16px}.card .card{box-shadow:none}.card-borderless,.card-borderless .card-header,.card-borderless .card-footer{border-color:transparent}.card-stamp{--tblr-stamp-size: 7rem;position:absolute;top:0;right:0;width:calc(var(--tblr-stamp-size) * 1);height:calc(var(--tblr-stamp-size) * 1);max-height:100%;border-top-right-radius:4px;opacity:.2;overflow:hidden;pointer-events:none}.card-stamp-lg{--tblr-stamp-size: 13rem}.card-stamp-icon{background:var(--tblr-secondary);color:var(--tblr-card-bg, var(--tblr-bg-surface));display:flex;align-items:center;justify-content:center;border-radius:100rem;width:calc(var(--tblr-stamp-size) * 1);height:calc(var(--tblr-stamp-size) * 1);position:relative;top:calc(var(--tblr-stamp-size) * -.25);right:calc(var(--tblr-stamp-size) * -.25);font-size:calc(var(--tblr-stamp-size) * .75);transform:rotate(10deg)}.card-stamp-icon .icon{stroke-width:2;width:calc(var(--tblr-stamp-size) * .75);height:calc(var(--tblr-stamp-size) * .75)}.card-img,.card-img-start{border-top-left-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)));border-bottom-left-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)))}.card-img,.card-img-end{border-top-right-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)));border-bottom-right-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)))}.card-img-overlay{display:flex;flex-direction:column;justify-content:flex-end}.card-img-overlay-dark{background-image:linear-gradient(180deg,#0000,#0009)}.card-inactive{pointer-events:none;box-shadow:none}.card-inactive .card-body{opacity:.64}.card-active{--tblr-card-border-color: var(--tblr-primary);--tblr-card-bg: var(--tblr-active-bg)}.card-btn{display:flex;align-items:center;justify-content:center;padding:1rem 1.25rem;text-align:center;transition:background .3s;border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);flex:1;color:inherit;font-weight:var(--tblr-font-weight-medium)}@media (prefers-reduced-motion: reduce){.card-btn{transition:none}}.card-btn:hover{text-decoration:none;background:rgba(var(--tblr-primary-rgb),.04)}.card-btn+.card-btn{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-stacked{--tblr-card-stacked-offset: .25rem;position:relative}.card-stacked:after{position:absolute;top:calc(-1 * var(--tblr-card-stacked-offset));right:var(--tblr-card-stacked-offset);left:var(--tblr-card-stacked-offset);height:var(--tblr-card-stacked-offset);content:"";background:var(--tblr-card-bg, var(--tblr-bg-surface));border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-card-border-color);border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-cover{position:relative;padding:1rem 1.25rem;background:#666 no-repeat center/cover}.card-cover:before{position:absolute;inset:0;content:"";background:#1824337a}.card-cover:first-child,.card-cover:first-child:before{border-radius:4px 4px 0 0}.card-cover-blurred:before{backdrop-filter:blur(2px)}.card-actions{margin:-.5rem -.5rem -.5rem auto;padding-left:.5rem}.card-actions a{text-decoration:none}.card-header{color:inherit;display:flex;align-items:center;background:transparent}.card-header:first-child{border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-header-light{border-bottom-color:transparent;background:var(--tblr-bg-surface-tertiary)}.card-header-tabs{background:var(--tblr-bg-surface-tertiary);flex:1;margin:calc(var(--tblr-card-cap-padding-y) * -1) calc(var(--tblr-card-cap-padding-x) * -1) calc(var(--tblr-card-cap-padding-y) * -1);padding:calc(var(--tblr-card-cap-padding-y) * .5) calc(var(--tblr-card-cap-padding-x) * .5) 0}.card-header-pills{flex:1;margin-top:-.5rem;margin-bottom:-.5rem}.card-rotate-left{transform:rotate(-1.5deg)}.card-rotate-right{transform:rotate(1.5deg)}.card-link{color:inherit}.card-link:hover{color:inherit;text-decoration:none;box-shadow:0 1px 6px #00000014}.card-link-rotate:hover{transform:rotate(1.5deg);opacity:1}.card-link-pop:hover{transform:translateY(-2px);opacity:1}.card-footer{margin-top:auto}.card-footer:last-child{border-radius:0 0 var(--tblr-card-border-radius) var(--tblr-card-border-radius)}.card-footer-transparent{background:transparent;border-color:transparent;padding-top:0}.card-footer-borderless{border-top:none}.card-progress{height:.25rem}.card-progress:last-child{border-radius:0 0 2px 2px}.card-progress:first-child{border-radius:2px 2px 0 0}.card-meta{color:var(--tblr-secondary)}.card-title{display:block;margin:0 0 1rem;font-size:1rem;font-weight:var(--tblr-font-weight-medium);color:inherit;line-height:1.5rem}a.card-title:hover{color:inherit}.card-header .card-title{margin:0}.card-subtitle{margin-bottom:1.25rem;color:var(--tblr-secondary);font-weight:400}.card-header .card-subtitle{margin:0}.card-title .card-subtitle{margin:0 0 0 .25rem;font-size:.875rem}.card-body{position:relative}.card-body>:last-child{margin-bottom:0}.card-sm>.card-body{padding:1rem}@media (min-width: 768px){.card-md>.card-body{padding:2.5rem}}@media (min-width: 768px){.card-lg>.card-body{padding:2rem}}@media (min-width: 992px){.card-lg>.card-body{padding:4rem}}@media print{.card-body{padding:0}}.card-body+.card-body{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-body-scrollable{overflow:auto}.card-options{top:1.5rem;right:.75rem;display:flex;margin-left:auto}.card-options-link{display:inline-block;min-width:1rem;margin-left:.25rem;color:var(--tblr-secondary)}.card-status-top{position:absolute;top:0;right:0;left:0;height:2px;border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-status-start{position:absolute;right:auto;bottom:0;width:2px;height:100%;border-radius:var(--tblr-card-border-radius) 0 0 var(--tblr-card-border-radius)}.card-status-bottom{position:absolute;top:initial;bottom:0;width:100%;height:2px;border-radius:0 0 var(--tblr-card-border-radius) var(--tblr-card-border-radius)}.card-table{margin-bottom:0!important}.card-table tr td:first-child,.card-table tr th:first-child{padding-left:1.25rem;border-left:0}.card-table tr td:last-child,.card-table tr th:last-child{padding-right:1.25rem;border-right:0}.card-table thead tr:first-child,.card-table tbody tr:first-child,.card-table tfoot tr:first-child,.card-table thead tr:first-child td,.card-table thead tr:first-child th,.card-table tbody tr:first-child td,.card-table tbody tr:first-child th,.card-table tfoot tr:first-child td,.card-table tfoot tr:first-child th{border-top:0}.card-body+.card-table{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-table-border-color)}.card-code{padding:0}.card-code .highlight{margin:0;border:0}.card-code pre{margin:0!important;border:0!important}.card-chart{position:relative;z-index:1;height:3.5rem}.card-avatar{margin-left:auto;margin-right:auto;box-shadow:0 0 0 .25rem var(--tblr-card-bg, var(--tblr-bg-surface));margin-top:calc(-1 * var(--tblr-avatar-size) * .5)}.card-body+.card-list-group{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-list-group .list-group-item{padding-right:1.25rem;padding-left:1.25rem;border-right:0;border-left:0;border-radius:0}.card-list-group .list-group-item:last-child{border-bottom:0}.card-list-group .list-group-item:first-child{border-top:0}.card-tabs .nav-tabs{position:relative;z-index:1000;border-bottom:0}.card-tabs .nav-tabs .nav-link{background:var(--tblr-bg-surface-tertiary);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.card-tabs .nav-tabs .nav-link.active,.card-tabs .nav-tabs .nav-link:active,.card-tabs .nav-tabs .nav-link:hover{border-color:var(--tblr-border-color-translucent);color:var(--tblr-body-color)}.card-tabs .nav-tabs .nav-link.active{color:inherit;background:var(--tblr-card-bg, var(--tblr-bg-surface));border-bottom-color:transparent}.card-tabs .nav-tabs .nav-item:not(:first-child) .nav-link{border-top-left-radius:0}.card-tabs .nav-tabs .nav-item:not(:last-child) .nav-link{border-top-right-radius:0}.card-tabs .nav-tabs .nav-item+.nav-item{margin-left:calc(-1 * var(--tblr-border-width))}.card-tabs .nav-tabs-bottom,.card-tabs .nav-tabs-bottom .nav-link{margin-bottom:0}.card-tabs .nav-tabs-bottom .nav-link.active{border-top-color:transparent}.card-tabs .nav-tabs-bottom .nav-item{margin-top:calc(-1 * var(--tblr-border-width));margin-bottom:0}.card-tabs .nav-tabs-bottom .nav-item .nav-link{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-radius:0 0 var(--tblr-border-radius) var(--tblr-border-radius)}.card-tabs .nav-tabs-bottom .nav-item:not(:first-child) .nav-link{border-bottom-left-radius:0}.card-tabs .nav-tabs-bottom .nav-item:not(:last-child) .nav-link{border-bottom-right-radius:0}.card-tabs .card{border-bottom-left-radius:0}.card-tabs .nav-tabs+.tab-content .card{border-bottom-left-radius:var(--tblr-card-border-radius);border-top-left-radius:0}.card-note{--tblr-card-bg: #fff7dd;--tblr-card-border-color: #fff1c9}.btn-close{cursor:pointer}.btn-close:focus{outline:none}.dropdown-menu{user-select:none;background-clip:border-box}.dropdown-menu.card{padding:0;min-width:25rem;display:none}.dropdown-menu.card.show{display:flex}.dropdown-item{min-width:11rem;display:flex;align-items:center;margin:0;line-height:1.4285714286}.dropdown-item-icon{width:1.25rem!important;height:1.25rem!important;margin-right:.5rem;color:var(--tblr-secondary);opacity:.7;text-align:center}.dropdown-item-indicator{margin-right:.5rem;margin-left:-.25rem;height:1.25rem;display:inline-flex;line-height:1;vertical-align:bottom;align-items:center}.dropdown-header{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);padding-bottom:.25rem;pointer-events:none}.dropdown-menu-scrollable{height:auto;max-height:13rem;overflow-x:hidden}.dropdown-menu-column{min-width:11rem}.dropdown-menu-column .dropdown-item{min-width:0}.dropdown-menu-columns{display:flex;flex:0 .25rem}.dropdown-menu-arrow:before{content:"";position:absolute;top:-.25rem;left:.75rem;display:block;background:inherit;width:14px;height:14px;transform:rotate(45deg);transform-origin:center;border:1px solid;border-color:inherit;z-index:-1;clip:rect(0px,9px,9px,0px)}.dropdown-menu-arrow.dropdown-menu-end:before{right:.75rem;left:auto}.dropend>.dropdown-menu{margin-top:calc(-.25rem - 1px);margin-left:-.25rem}.dropend .dropdown-toggle:after{margin-left:auto}.dropdown-menu-card{padding:0}.dropdown-menu-card>.card{margin:0;border:0;box-shadow:none}.datagrid{--tblr-datagrid-padding: 1.5rem;--tblr-datagrid-item-width: 15rem;display:grid;grid-gap:var(--tblr-datagrid-padding);grid-template-columns:repeat(auto-fit,minmax(var(--tblr-datagrid-item-width),1fr))}.datagrid-title{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);margin-bottom:.25rem}.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:1rem;text-align:center}@media (min-width: 768px){.empty{padding:3rem}}.empty-icon{margin:0 0 1rem;width:3rem;height:3rem;line-height:1;color:var(--tblr-secondary)}.empty-icon svg{width:100%;height:100%}.empty-img{margin:0 0 2rem;line-height:1}.empty-header{margin:0 0 1rem;font-size:4rem;font-weight:var(--tblr-font-weight-light);line-height:1;color:var(--tblr-secondary)}.empty-title{font-size:1.25rem;line-height:1.75rem;font-weight:var(--tblr-font-weight-bold)}.empty-title,.empty-subtitle{margin:0 0 .5rem}.empty-action{margin-top:1.5rem}.empty-bordered{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.row>*{min-width:0}.col-separator{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.container-slim{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:16rem}.container-tight{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:30rem}.container-narrow{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:45rem}.row-0{margin-right:0;margin-left:0}.row-0>.col,.row-0>[class*=col-]{padding-right:0;padding-left:0}.row-0 .card{margin-bottom:0}.row-sm{margin-right:-.375rem;margin-left:-.375rem}.row-sm>.col,.row-sm>[class*=col-]{padding-right:.375rem;padding-left:.375rem}.row-sm .card{margin-bottom:.75rem}.row-md{margin-right:-1.5rem;margin-left:-1.5rem}.row-md>.col,.row-md>[class*=col-]{padding-right:1.5rem;padding-left:1.5rem}.row-md .card{margin-bottom:3rem}.row-lg{margin-right:-3rem;margin-left:-3rem}.row-lg>.col,.row-lg>[class*=col-]{padding-right:3rem;padding-left:3rem}.row-lg .card{margin-bottom:6rem}.row-deck>.col,.row-deck>[class*=col-]{display:flex;align-items:stretch}.row-deck>.col .card,.row-deck>[class*=col-] .card{flex:1 1 auto}.row-cards{--tblr-gutter-x: var(--tblr-page-padding);--tblr-gutter-y: var(--tblr-page-padding);min-width:0}.row-cards .row-cards{flex:1}.space-y{display:flex;flex-direction:column;gap:1rem}.space-x{display:flex;gap:1rem}.space-y-0{display:flex;flex-direction:column;gap:0}.space-x-0{display:flex;gap:0}.space-y-1{display:flex;flex-direction:column;gap:.25rem}.space-x-1{display:flex;gap:.25rem}.space-y-2{display:flex;flex-direction:column;gap:.5rem}.space-x-2{display:flex;gap:.5rem}.space-y-3{display:flex;flex-direction:column;gap:1rem}.space-x-3{display:flex;gap:1rem}.space-y-4{display:flex;flex-direction:column;gap:1.5rem}.space-x-4{display:flex;gap:1.5rem}.space-y-5{display:flex;flex-direction:column;gap:2rem}.space-x-5{display:flex;gap:2rem}.space-y-6{display:flex;flex-direction:column;gap:3rem}.space-x-6{display:flex;gap:3rem}.space-y-7{display:flex;flex-direction:column;gap:5rem}.space-x-7{display:flex;gap:5rem}.space-y-8{display:flex;flex-direction:column;gap:8rem}.space-x-8{display:flex;gap:8rem}.divide-y>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y>:not(template):not(:first-child){padding-top:1rem!important}.divide-y>:not(template):not(:last-child){padding-bottom:1rem!important}.divide-x>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x>:not(template):not(:first-child){padding-left:1rem!important}.divide-x>:not(template):not(:last-child){padding-right:1rem!important}.divide-y-0>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-0>:not(template):not(:first-child){padding-top:0!important}.divide-y-0>:not(template):not(:last-child){padding-bottom:0!important}.divide-x-0>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-0>:not(template):not(:first-child){padding-left:0!important}.divide-x-0>:not(template):not(:last-child){padding-right:0!important}.divide-y-1>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-1>:not(template):not(:first-child){padding-top:.25rem!important}.divide-y-1>:not(template):not(:last-child){padding-bottom:.25rem!important}.divide-x-1>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-1>:not(template):not(:first-child){padding-left:.25rem!important}.divide-x-1>:not(template):not(:last-child){padding-right:.25rem!important}.divide-y-2>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-2>:not(template):not(:first-child){padding-top:.5rem!important}.divide-y-2>:not(template):not(:last-child){padding-bottom:.5rem!important}.divide-x-2>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-2>:not(template):not(:first-child){padding-left:.5rem!important}.divide-x-2>:not(template):not(:last-child){padding-right:.5rem!important}.divide-y-3>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-3>:not(template):not(:first-child){padding-top:1rem!important}.divide-y-3>:not(template):not(:last-child){padding-bottom:1rem!important}.divide-x-3>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-3>:not(template):not(:first-child){padding-left:1rem!important}.divide-x-3>:not(template):not(:last-child){padding-right:1rem!important}.divide-y-4>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-4>:not(template):not(:first-child){padding-top:1.5rem!important}.divide-y-4>:not(template):not(:last-child){padding-bottom:1.5rem!important}.divide-x-4>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-4>:not(template):not(:first-child){padding-left:1.5rem!important}.divide-x-4>:not(template):not(:last-child){padding-right:1.5rem!important}.divide-y-5>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-5>:not(template):not(:first-child){padding-top:2rem!important}.divide-y-5>:not(template):not(:last-child){padding-bottom:2rem!important}.divide-x-5>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-5>:not(template):not(:first-child){padding-left:2rem!important}.divide-x-5>:not(template):not(:last-child){padding-right:2rem!important}.divide-y-6>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-6>:not(template):not(:first-child){padding-top:3rem!important}.divide-y-6>:not(template):not(:last-child){padding-bottom:3rem!important}.divide-x-6>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-6>:not(template):not(:first-child){padding-left:3rem!important}.divide-x-6>:not(template):not(:last-child){padding-right:3rem!important}.divide-y-7>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-7>:not(template):not(:first-child){padding-top:5rem!important}.divide-y-7>:not(template):not(:last-child){padding-bottom:5rem!important}.divide-x-7>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-7>:not(template):not(:first-child){padding-left:5rem!important}.divide-x-7>:not(template):not(:last-child){padding-right:5rem!important}.divide-y-8>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-8>:not(template):not(:first-child){padding-top:8rem!important}.divide-y-8>:not(template):not(:last-child){padding-bottom:8rem!important}.divide-x-8>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-8>:not(template):not(:first-child){padding-left:8rem!important}.divide-x-8>:not(template):not(:last-child){padding-right:8rem!important}.divide-y-fill{display:flex;flex-direction:column;height:100%}.divide-y-fill>:not(template){flex:1;display:flex;justify-content:center;flex-direction:column}.icon{--tblr-icon-size: 1.25rem;width:var(--tblr-icon-size);height:var(--tblr-icon-size);font-size:var(--tblr-icon-size);vertical-align:bottom;stroke-width:1.5}.icon:hover{text-decoration:none}.icon-inline{--tblr-icon-size: 1rem;vertical-align:-.2rem}.icon-filled{fill:currentColor}.icon-sm{--tblr-icon-size: 1rem;stroke-width:1}.icon-md{--tblr-icon-size: 2.5rem;stroke-width:1}.icon-lg{--tblr-icon-size: 3.5rem;stroke-width:1}.icon-pulse{transition:all .15s ease 0s;animation:pulse 2s ease infinite;animation-fill-mode:both}.icon-tada{transition:all .15s ease 0s;animation:tada 3s ease infinite;animation-fill-mode:both}.icon-rotate{transition:all .15s ease 0s;animation:rotate-360 3s linear infinite;animation-fill-mode:both}.img-responsive{--tblr-img-responsive-ratio: 75%;background:no-repeat center/cover;padding-top:var(--tblr-img-responsive-ratio)}.img-responsive-grid{padding-top:calc(var(--tblr-img-responsive-ratio) - var(--tblr-gutter-y) / 2)}.img-responsive-1x1{--tblr-img-responsive-ratio: 100%}.img-responsive-2x1{--tblr-img-responsive-ratio: 50%}.img-responsive-1x2{--tblr-img-responsive-ratio: 200%}.img-responsive-3x1{--tblr-img-responsive-ratio: 33.3333333333%}.img-responsive-1x3{--tblr-img-responsive-ratio: 300%}.img-responsive-4x3{--tblr-img-responsive-ratio: 75%}.img-responsive-3x4{--tblr-img-responsive-ratio: 133.3333333333%}.img-responsive-16x9{--tblr-img-responsive-ratio: 56.25%}.img-responsive-9x16{--tblr-img-responsive-ratio: 177.7777777778%}.img-responsive-21x9{--tblr-img-responsive-ratio: 42.8571428571%}.img-responsive-9x21{--tblr-img-responsive-ratio: 233.3333333333%}textarea[cols]{height:auto}.col-form-label,.form-label{display:block;font-weight:var(--tblr-font-weight-medium)}.col-form-label.required:after,.form-label.required:after{content:"*";margin-left:.25rem;color:#d63939}.form-label-description{float:right;font-weight:var(--tblr-font-weight-normal);color:var(--tblr-gray-500)}.form-hint{display:block;color:var(--tblr-gray-500)}.form-hint:last-child{margin-bottom:0}.form-hint+.form-control{margin-top:.25rem}.form-label+.form-hint{margin-top:-.25rem}.input-group+.form-hint,.form-control+.form-hint,.form-select+.form-hint{margin-top:.5rem;color:var(--tblr-gray-500)}.form-select:-moz-focusring{color:var(--tblr-body-color)}.form-control:-webkit-autofill{box-shadow:0 0 0 1000px var(--tblr-body-bg) inset;color:var(--tblr-body-color);-webkit-text-fill-color:var(--tblr-body-color)}.form-control:disabled,.form-control.disabled{color:var(--tblr-gray-500);user-select:none}.form-control[size]{width:auto}.form-control-light{background-color:var(--tblr-gray-100);border-color:transparent}.form-control-dark{background-color:#0000001a;color:#fff;border-color:transparent}.form-control-dark:focus{background-color:#0000001a;box-shadow:none;border-color:#ffffff3d}.form-control-dark::placeholder{color:#fff9}.form-control-rounded{border-radius:10rem}.form-control-flush{padding:0;background:none!important;border-color:transparent!important;resize:none;box-shadow:none!important;line-height:inherit}.form-footer{margin-top:2rem}.form-fieldset{padding:1rem;margin-bottom:1rem;background:var(--tblr-body-bg);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.form-help{display:inline-flex;font-weight:var(--tblr-font-weight-bold);align-items:center;justify-content:center;width:1.125rem;height:1.125rem;font-size:.75rem;color:var(--tblr-gray-500);text-align:center;text-decoration:none;cursor:pointer;user-select:none;background:var(--tblr-gray-100);border-radius:100rem;transition:background-color .3s,color .3s}@media (prefers-reduced-motion: reduce){.form-help{transition:none}}.form-help:hover,.form-help[aria-describedby]{color:#fff;background:var(--tblr-primary)}.input-group{box-shadow:var(--tblr-box-shadow-input);border-radius:var(--tblr-border-radius)}.input-group .form-control,.input-group .btn{box-shadow:none}.input-group-link{font-size:.75rem}.input-group-flat:focus-within{box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25);border-radius:var(--tblr-border-radius)}.input-group-flat:focus-within .form-control,.input-group-flat:focus-within .input-group-text{border-color:#80c2be!important}.input-group-flat .form-control:focus{border-color:var(--tblr-border-color);box-shadow:none}.input-group-flat .form-control:not(:last-child){border-right:0}.input-group-flat .form-control:not(:first-child){border-left:0}.input-group-flat .input-group-text{background:var(--tblr-bg-forms);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.input-group-flat .input-group-text{transition:none}}.input-group-flat .input-group-text:first-child{padding-right:0}.input-group-flat .input-group-text:last-child{padding-left:0}.form-file-button{margin-left:0;border-left:0}.input-icon{position:relative}.input-icon .form-control:not(:last-child),.input-icon .form-select:not(:last-child){padding-right:2.5rem}.input-icon .form-control:not(:first-child),.input-icon .form-select:not(:last-child){padding-left:2.5rem}.input-icon-addon{position:absolute;top:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;min-width:2.5rem;color:var(--tblr-icon-color);pointer-events:none;font-size:1.2em}.input-icon-addon:last-child{right:0;left:auto}.form-colorinput{position:relative;display:inline-block;margin:0;line-height:1;cursor:pointer}.form-colorinput-input{position:absolute;z-index:-1;opacity:0}.form-colorinput-color{display:block;width:1.5rem;height:1.5rem;color:#fff;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-radius:3px;box-shadow:0 1px 2px #0000000d}.form-colorinput-color:before{position:absolute;top:0;left:0;width:100%;height:100%;content:"";background:no-repeat center center/1.25rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e");opacity:0;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-colorinput-color:before{transition:none}}.form-colorinput-input:checked~.form-colorinput-color:before{opacity:1}.form-colorinput-input:focus~.form-colorinput-color{border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-colorinput-light .form-colorinput-color:before{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23182433' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-imagecheck{position:relative;margin:0;cursor:pointer}.form-imagecheck-input{position:absolute;z-index:-1;opacity:0}.form-imagecheck-figure{position:relative;display:block;margin:0;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:3px}.form-imagecheck-input:focus~.form-imagecheck-figure{border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-imagecheck-input:checked~.form-imagecheck-figure{border-color:var(--tblr-primary)}.form-imagecheck-figure:before{position:absolute;top:.25rem;left:.25rem;z-index:1;display:block;width:1.25rem;height:1.25rem;color:#fff;pointer-events:none;content:"";user-select:none;background:var(--tblr-bg-forms);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius);transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-figure:before{transition:none}}.form-imagecheck-input:checked~.form-imagecheck-figure:before{background-color:var(--tblr-primary);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e");background-repeat:repeat;background-position:center;background-size:1.25rem;border-color:var(--tblr-border-color-translucent)}.form-imagecheck-input[type=radio]~.form-imagecheck-figure:before{border-radius:50%}.form-imagecheck-input[type=radio]:checked~.form-imagecheck-figure:before{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-imagecheck-image{max-width:100%;display:block;opacity:.64;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-image{transition:none}}.form-imagecheck-image:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.form-imagecheck-image:last-child{border-bottom-right-radius:2px;border-bottom-left-radius:2px}.form-imagecheck:hover .form-imagecheck-image,.form-imagecheck-input:focus~.form-imagecheck-figure .form-imagecheck-image,.form-imagecheck-input:checked~.form-imagecheck-figure .form-imagecheck-image{opacity:1}.form-imagecheck-caption{padding:.25rem;font-size:.765625rem;color:var(--tblr-secondary);text-align:center;transition:color .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-caption{transition:none}}.form-imagecheck:hover .form-imagecheck-caption,.form-imagecheck-input:focus~.form-imagecheck-figure .form-imagecheck-caption,.form-imagecheck-input:checked~.form-imagecheck-figure .form-imagecheck-caption{color:var(--tblr-body-color)}.form-selectgroup{display:inline-flex;margin:0 -.5rem -.5rem 0;flex-wrap:wrap}.form-selectgroup .form-selectgroup-item{margin:0 .5rem .5rem 0}.form-selectgroup-vertical{flex-direction:column}.form-selectgroup-item{display:block;position:relative}.form-selectgroup-input{position:absolute;top:0;left:0;z-index:-1;opacity:0}.form-selectgroup-label{position:relative;display:block;min-width:calc(1.4285714286em + 1.125rem + calc(var(--tblr-border-width) * 2));margin:0;padding:.5625rem .75rem;font-size:.875rem;line-height:1.4285714286;color:var(--tblr-secondary);background:var(--tblr-bg-forms);text-align:center;cursor:pointer;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:3px;box-shadow:var(--tblr-box-shadow-input);transition:border-color .3s,background .3s,color .3s}@media (prefers-reduced-motion: reduce){.form-selectgroup-label{transition:none}}.form-selectgroup-label .icon:only-child{margin:0 -.25rem}.form-selectgroup-label:hover{color:var(--tblr-body-color)}.form-selectgroup-check{display:inline-block;width:1.25rem;height:1.25rem;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);vertical-align:middle;box-shadow:var(--tblr-box-shadow-input)}.form-selectgroup-input[type=checkbox]+.form-selectgroup-label .form-selectgroup-check{border-radius:var(--tblr-border-radius)}.form-selectgroup-input[type=radio]+.form-selectgroup-label .form-selectgroup-check{border-radius:50%}.form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-check{background-color:var(--tblr-primary);background-repeat:repeat;background-position:center;background-size:1.25rem;border-color:var(--tblr-border-color-translucent)}.form-selectgroup-input[type=checkbox]:checked+.form-selectgroup-label .form-selectgroup-check{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-selectgroup-input[type=radio]:checked+.form-selectgroup-label .form-selectgroup-check{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-selectgroup-check-floated{position:absolute;top:.5625rem;right:.5625rem}.form-selectgroup-input:checked+.form-selectgroup-label{z-index:1;color:var(--tblr-primary);background:rgba(var(--tblr-primary-rgb),.04);border-color:var(--tblr-primary)}.form-selectgroup-input:focus+.form-selectgroup-label{z-index:2;color:var(--tblr-primary);border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-selectgroup-boxes .form-selectgroup-label{text-align:left;padding:1.25rem 1rem;color:inherit}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label{color:inherit}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-title{color:var(--tblr-primary)}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-label-content{opacity:1}.form-selectgroup-pills{flex-wrap:wrap;align-items:flex-start}.form-selectgroup-pills .form-selectgroup-item{flex-grow:0}.form-selectgroup-pills .form-selectgroup-label{border-radius:50px}.form-control-color::-webkit-color-swatch{border:none}[type=search]::-webkit-search-cancel-button{-webkit-appearance:none}.form-control::file-selector-button{background-color:var(--tblr-btn-color, var(--tblr-tertiary-bg))}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--tblr-btn-color, var(--tblr-secondary-bg))}.form-check{user-select:none}.form-check.form-check-highlight .form-check-input:not(:checked)~.form-check-label{color:var(--tblr-secondary)}.form-check .form-check-label-off{color:var(--tblr-secondary)}.form-check .form-check-input:checked~.form-check-label-off{display:none}.form-check .form-check-input:not(:checked)~.form-check-label-on{display:none}.form-check-input{background-size:1.25rem;margin-top:0rem;box-shadow:var(--tblr-box-shadow-input)}.form-switch .form-check-input{transition:background-color .3s,background-position .3s}@media (prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-check-label{display:block}.form-check-label.required:after{content:"*";margin-left:.25rem;color:#d63939}.form-check-description{display:block;color:var(--tblr-secondary);font-size:.75rem;margin-top:.25rem}.form-check-single,.form-check-single .form-check-input{margin:0}.form-switch .form-check-input{height:1.25rem;margin-top:0rem}.form-switch-lg{padding-left:3.5rem;min-height:1.5rem}.form-switch-lg .form-check-input{height:1.5rem;width:2.75rem;background-size:1.5rem;margin-left:-3.5rem}.form-switch-lg .form-check-label{padding-top:.125rem}.form-check-input:checked{border:none}.form-select.is-invalid-lite,.form-control.is-invalid-lite,.form-select.is-valid-lite,.form-control.is-valid-lite{border-color:var(--tblr-border-color)!important}.legend{--tblr-legend-size: .75em;display:inline-block;background:var(--tblr-border-color);width:var(--tblr-legend-size);height:var(--tblr-legend-size);border-radius:var(--tblr-border-radius-sm);border:1px solid var(--tblr-border-color-translucent)}.list-group{margin-left:0;margin-right:0}.list-group-header{background:var(--tblr-bg-surface-tertiary);padding:.5rem 1.25rem;font-size:.75rem;font-weight:var(--tblr-font-weight-medium);line-height:1;text-transform:uppercase;color:var(--tblr-gray-500);border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.list-group-flush>.list-group-header:last-child{border-bottom-width:0}.list-group-item{background-color:inherit}.list-group-item.active{background-color:rgba(var(--tblr-secondary-rgb),.08);border-left-color:#00857d;border-left-width:2px}.list-group-item:active,.list-group-item:focus,.list-group-item:hover{background-color:rgba(var(--tblr-secondary-rgb),.08)}.list-group-item.disabled,.list-group-item:disabled{color:#6c7a91;background-color:rgba(var(--tblr-secondary-rgb),.08)}.list-bordered .list-item{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);margin-top:-1px}.list-bordered .list-item:first-child{border-top:none}.list-group-hoverable .list-group-item-actions{opacity:0;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.list-group-hoverable .list-group-item-actions{transition:none}}.list-group-hoverable .list-group-item:hover .list-group-item-actions,.list-group-hoverable .list-group-item-actions.show{opacity:1}.list-group-transparent{--tblr-list-group-border-radius: 0;margin:0 -1.25rem}.list-group-transparent .list-group-item{background:none;border:0}.list-group-transparent .list-group-item .icon{color:var(--tblr-secondary)}.list-group-transparent .list-group-item.active{font-weight:var(--tblr-font-weight-bold);color:inherit;background:var(--tblr-active-bg)}.list-group-transparent .list-group-item.active .icon{color:inherit}.list-separated-item{padding:1rem 0}.list-separated-item:first-child{padding-top:0}.list-separated-item:last-child{padding-bottom:0}.list-separated-item+.list-separated-item{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.list-inline-item:not(:last-child){margin-right:auto;margin-inline-end:.5rem}.list-inline-dots .list-inline-item+.list-inline-item:before{content:" \b7 ";margin-inline-end:.5rem}.loader{position:relative;display:block;width:2.5rem;height:2.5rem;color:#066fd1;vertical-align:middle}.loader:after{position:absolute;top:0;left:0;width:100%;height:100%;content:"";border:1px var(--tblr-border-style);border-color:transparent;border-top-color:currentColor;border-left-color:currentColor;border-radius:100rem;animation:rotate-360 .6s linear;animation-iteration-count:infinite}.dimmer{position:relative}.dimmer .loader{position:absolute;top:50%;right:0;left:0;display:none;margin:0 auto;transform:translateY(-50%)}.dimmer.active .loader{display:block}.dimmer.active .dimmer-content{pointer-events:none;opacity:.1}@keyframes animated-dots{0%{transform:translate(-100%)}}.animated-dots{display:inline-block;overflow:hidden;vertical-align:bottom}.animated-dots:after{display:inline-block;content:"...";animation:animated-dots 1.2s steps(4,jump-none) infinite}.modal-content>.btn-close,.modal-header>.btn-close{position:absolute;top:0;right:0;width:3.5rem;height:3.5rem;margin:0;padding:0;z-index:10}.modal-body{scrollbar-color:rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}.modal-body::-webkit-scrollbar{width:1rem;height:1rem;transition:background .3s}@media (prefers-reduced-motion: reduce){.modal-body::-webkit-scrollbar{transition:none}}.modal-body::-webkit-scrollbar-thumb{border-radius:1rem;border:5px solid transparent;box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}.modal-body::-webkit-scrollbar-track{background:transparent}.modal-body:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.32)}.modal-body::-webkit-scrollbar-corner{background:transparent}.modal-body .modal-title{margin-bottom:1rem}.modal-body+.modal-body{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.modal-status{position:absolute;top:0;left:0;right:0;height:2px;background:var(--tblr-secondary);border-radius:var(--tblr-border-radius-lg) var(--tblr-border-radius-lg) 0 0}.modal-header{align-items:center;min-height:3.5rem;background:transparent;padding:0 3.5rem 0 1.5rem}.modal-title{font-size:1rem;font-weight:var(--tblr-font-weight-bold);color:inherit;line-height:1.4285714286}.modal-footer{padding-top:.75rem;padding-bottom:.75rem}.modal-blur{backdrop-filter:blur(4px)}.modal-full-width{max-width:none;margin:0 .5rem}.nav-vertical,.nav-vertical .nav{flex-direction:column;flex-wrap:nowrap}.nav-vertical .nav{margin-left:1.25rem;border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);padding-left:.5rem}.nav-vertical .nav-link.active,.nav-vertical .nav-item.show .nav-link{font-weight:var(--tblr-font-weight-bold)}.nav-vertical.nav-pills{margin:0 -.75rem}.nav-bordered{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.nav-bordered .nav-item+.nav-item{margin-left:1.25rem}.nav-bordered .nav-link{padding-left:0;padding-right:0;margin:0 0 -var(--tblr-border-width);border:0;border-bottom:2px var(--tblr-border-style) transparent;color:var(--tblr-secondary)}.nav-bordered .nav-link.active,.nav-bordered .nav-item.show .nav-link{color:var(--tblr-primary);border-color:var(--tblr-primary)}.nav-link{display:flex;transition:color .3s;align-items:center}@media (prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link-toggle{margin-left:auto;padding:0 .25rem;transition:transform .3s}@media (prefers-reduced-motion: reduce){.nav-link-toggle{transition:none}}.nav-link-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-45deg)}.nav-link-toggle:after{margin:0}.nav-link[aria-expanded=true] .nav-link-toggle{transform:rotate(180deg)}.nav-link-icon{width:1.25rem;height:1.25rem;margin-right:.5rem;color:var(--tblr-icon-color)}.nav-link-icon svg{display:block;height:100%}.nav-fill .nav-item .nav-link{justify-content:center}.stars{display:inline-flex;color:#8a97ab;font-size:.75rem}.stars .star:not(:first-child){margin-left:.25rem}.pagination{user-select:none}.page-link{min-width:1.75rem;border-radius:var(--tblr-border-radius)}.page-item{text-align:center}.page-item:not(.active) .page-link:hover{background:transparent}.page-item.page-prev,.page-item.page-next{flex:0 0 50%;text-align:left}.page-item.page-next{margin-left:auto;text-align:right}.page-item-subtitle{margin-bottom:2px;font-size:12px;color:var(--tblr-secondary);text-transform:uppercase}.page-item.disabled .page-item-subtitle{color:var(--tblr-disabled-color)}.page-item-title{font-size:1rem;font-weight:var(--tblr-font-weight-normal);color:var(--tblr-body-color)}.page-link:hover .page-item-title{color:#00857d}.page-item.disabled .page-item-title{color:var(--tblr-disabled-color)}@keyframes progress-indeterminate{0%{right:100%;left:-35%}to,60%{right:-90%;left:100%}}.progress{position:relative;width:100%;line-height:.5rem;appearance:none}.progress::-webkit-progress-bar{background:var(--tblr-progress-bg)}.progress::-webkit-progress-value{background-color:var(--tblr-primary)}.progress::-moz-progress-bar{background-color:var(--tblr-primary)}.progress::-ms-fill{background-color:var(--tblr-primary);border:none}.progress-sm{height:.25rem}.progress-bar{height:100%}.progress-bar-indeterminate:after,.progress-bar-indeterminate:before{position:absolute;top:0;bottom:0;left:0;content:"";background-color:inherit;will-change:left,right}.progress-bar-indeterminate:before{animation:progress-indeterminate 1.5s cubic-bezier(.65,.815,.735,.395) infinite}.progress-separated .progress-bar{box-shadow:0 0 0 2px var(--tblr-card-bg, var(--tblr-bg-surface))}.progressbg{position:relative;padding:.25rem .5rem;display:flex}.progressbg-text{position:relative;z-index:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.progressbg-progress{position:absolute;inset:0;z-index:0;height:100%;background:transparent;pointer-events:none}.progressbg-value{font-weight:var(--tblr-font-weight-medium);margin-left:auto;padding-left:2rem}.ribbon{--tblr-ribbon-margin: .25rem;--tblr-ribbon-border-radius: var(--tblr-border-radius);position:absolute;top:.75rem;right:calc(-1 * var(--tblr-ribbon-margin));z-index:1;padding:.25rem .75rem;font-size:.625rem;font-weight:var(--tblr-font-weight-bold);line-height:1;color:#fff;text-align:center;text-transform:uppercase;background:var(--tblr-primary);border-color:var(--tblr-primary);border-radius:var(--tblr-ribbon-border-radius) 0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius);display:inline-flex;align-items:center;justify-content:center;min-height:2rem;min-width:2rem}.ribbon:before{position:absolute;right:0;bottom:100%;width:0;height:0;content:"";filter:brightness(70%);border:calc(var(--tblr-ribbon-margin) * .5) var(--tblr-border-style);border-color:inherit;border-top-color:transparent;border-right-color:transparent}.ribbon.bg-blue{border-color:var(--tblr-blue)}.ribbon.bg-blue-lt{border-color:rgba(var(--tblr-blue-rgb),.1)!important}.ribbon.bg-azure{border-color:var(--tblr-azure)}.ribbon.bg-azure-lt{border-color:rgba(var(--tblr-azure-rgb),.1)!important}.ribbon.bg-indigo{border-color:var(--tblr-indigo)}.ribbon.bg-indigo-lt{border-color:rgba(var(--tblr-indigo-rgb),.1)!important}.ribbon.bg-purple{border-color:var(--tblr-purple)}.ribbon.bg-purple-lt{border-color:rgba(var(--tblr-purple-rgb),.1)!important}.ribbon.bg-pink{border-color:var(--tblr-pink)}.ribbon.bg-pink-lt{border-color:rgba(var(--tblr-pink-rgb),.1)!important}.ribbon.bg-red{border-color:var(--tblr-red)}.ribbon.bg-red-lt{border-color:rgba(var(--tblr-red-rgb),.1)!important}.ribbon.bg-orange{border-color:var(--tblr-orange)}.ribbon.bg-orange-lt{border-color:rgba(var(--tblr-orange-rgb),.1)!important}.ribbon.bg-yellow{border-color:var(--tblr-yellow)}.ribbon.bg-yellow-lt{border-color:rgba(var(--tblr-yellow-rgb),.1)!important}.ribbon.bg-lime{border-color:var(--tblr-lime)}.ribbon.bg-lime-lt{border-color:rgba(var(--tblr-lime-rgb),.1)!important}.ribbon.bg-green{border-color:var(--tblr-green)}.ribbon.bg-green-lt{border-color:rgba(var(--tblr-green-rgb),.1)!important}.ribbon.bg-teal{border-color:var(--tblr-teal)}.ribbon.bg-teal-lt{border-color:rgba(var(--tblr-teal-rgb),.1)!important}.ribbon.bg-cyan{border-color:var(--tblr-cyan)}.ribbon.bg-cyan-lt{border-color:rgba(var(--tblr-cyan-rgb),.1)!important}.ribbon .icon{width:1.25rem;height:1.25rem;font-size:1.25rem}.ribbon-top{top:calc(-1 * var(--tblr-ribbon-margin));right:.75rem;width:2rem;padding:.5rem 0;border-radius:0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius)}.ribbon-top:before{top:0;right:100%;bottom:auto;border-color:inherit;border-top-color:transparent;border-left-color:transparent}.ribbon-top.ribbon-start{right:auto;left:.75rem}.ribbon-top.ribbon-start:before{top:0;right:100%;left:auto}.ribbon-start{right:auto;left:calc(-1 * var(--tblr-ribbon-margin));border-radius:0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius)}.ribbon-start:before{top:auto;bottom:100%;left:0;border-color:inherit;border-top-color:transparent;border-left-color:transparent}.ribbon-bottom{top:auto;bottom:.75rem}.ribbon-bookmark{padding-left:.25rem;border-radius:0 0 var(--tblr-ribbon-border-radius) 0}.ribbon-bookmark:after{position:absolute;top:0;right:100%;display:block;width:0;height:0;content:"";border:1rem var(--tblr-border-style);border-color:inherit;border-right-width:0;border-left-color:transparent;border-left-width:.5rem}.ribbon-bookmark.ribbon-left{padding-right:.5rem}.ribbon-bookmark.ribbon-left:after{right:auto;left:100%;border-right-color:transparent;border-right-width:.5rem;border-left-width:0}.ribbon-bookmark.ribbon-top{padding-right:0;padding-bottom:.25rem;padding-left:0;border-radius:0 var(--tblr-ribbon-border-radius) 0 0}.ribbon-bookmark.ribbon-top:after{top:100%;right:0;left:0;border-color:inherit;border-width:1rem;border-top-width:0;border-bottom-color:transparent;border-bottom-width:.5rem}.markdown{line-height:1.7142857143}.markdown>:first-child{margin-top:0}.markdown>:last-child,.markdown>:last-child .highlight{margin-bottom:0}@media (min-width: 768px){.markdown>hr,.markdown>.hr{margin-top:3em;margin-bottom:3em}}.markdown>h1,.markdown>.h1,.markdown>h2,.markdown>.h2,.markdown>h3,.markdown>.h3,.markdown>h4,.markdown>.h4,.markdown>h5,.markdown>.h5,.markdown>h6,.markdown>.h6{font-weight:var(--tblr-font-weight-bold)}.markdown>blockquote{font-size:1rem;margin:1.5rem 0;padding:.5rem 1.5rem}.markdown>img{border-radius:var(--tblr-border-radius)}.placeholder:not(.btn):not([class*=bg-]){background-color:currentColor!important}.placeholder:not(.avatar):not([class*=card-img-]){border-radius:var(--tblr-border-radius)}.steps{--tblr-steps-color: var(--tblr-primary);--tblr-steps-inactive-color: var(--tblr-border-color);--tblr-steps-dot-size: .5rem;--tblr-steps-border-width: 2px;display:flex;flex-wrap:nowrap;width:100%;padding:0;margin:0;list-style:none}.steps-blue{--tblr-steps-color: var(--tblr-blue)}.steps-azure{--tblr-steps-color: var(--tblr-azure)}.steps-indigo{--tblr-steps-color: var(--tblr-indigo)}.steps-purple{--tblr-steps-color: var(--tblr-purple)}.steps-pink{--tblr-steps-color: var(--tblr-pink)}.steps-red{--tblr-steps-color: var(--tblr-red)}.steps-orange{--tblr-steps-color: var(--tblr-orange)}.steps-yellow{--tblr-steps-color: var(--tblr-yellow)}.steps-lime{--tblr-steps-color: var(--tblr-lime)}.steps-green{--tblr-steps-color: var(--tblr-green)}.steps-teal{--tblr-steps-color: var(--tblr-teal)}.steps-cyan{--tblr-steps-color: var(--tblr-cyan)}.step-item{position:relative;flex:1 1 0;min-height:1rem;margin-top:0;color:inherit;text-align:center;cursor:default;padding-top:calc(var(--tblr-steps-dot-size))}a.step-item{cursor:pointer}a.step-item:hover{color:inherit}.step-item:after,.step-item:before{background:var(--tblr-steps-color)}.step-item:not(:last-child):after{position:absolute;left:50%;width:100%;content:"";transform:translateY(-50%)}.step-item:after{top:calc(var(--tblr-steps-dot-size) * .5);height:var(--tblr-steps-border-width)}.step-item:before{content:"";position:absolute;top:0;left:50%;z-index:1;box-sizing:content-box;display:flex;align-items:center;justify-content:center;border-radius:100rem;transform:translate(-50%);color:var(--tblr-white);width:var(--tblr-steps-dot-size);height:var(--tblr-steps-dot-size)}.step-item.active{font-weight:var(--tblr-font-weight-bold)}.step-item.active:after{background:var(--tblr-steps-inactive-color)}.step-item.active~.step-item{color:var(--tblr-disabled-color)}.step-item.active~.step-item:after,.step-item.active~.step-item:before{background:var(--tblr-steps-inactive-color)}.steps-counter{--tblr-steps-dot-size: 1.5rem;counter-reset:steps}.steps-counter .step-item{counter-increment:steps}.steps-counter .step-item:before{content:counter(steps)}.steps-vertical{--tblr-steps-dot-offset: 6px;flex-direction:column}.steps-vertical.steps-counter{--tblr-steps-dot-offset: -2px}.steps-vertical .step-item{text-align:left;padding-top:0;padding-left:calc(var(--tblr-steps-dot-size) + 1rem);min-height:auto}.steps-vertical .step-item:not(:first-child){margin-top:1rem}.steps-vertical .step-item:before{top:var(--tblr-steps-dot-offset);left:0;transform:translate(0)}.steps-vertical .step-item:not(:last-child):after{position:absolute;content:"";transform:translate(-50%);top:var(--tblr-steps-dot-offset);left:calc(var(--tblr-steps-dot-size) * .5);width:var(--tblr-steps-border-width);height:calc(100% + 1rem)}@keyframes status-pulsate-main{40%{transform:scale(1.25)}60%{transform:scale(1.25)}}@keyframes status-pulsate-secondary{10%{transform:scale(1)}30%{transform:scale(3)}80%{transform:scale(3)}to{transform:scale(1)}}@keyframes status-pulsate-tertiary{25%{transform:scale(1)}80%{transform:scale(3);opacity:0}to{transform:scale(3);opacity:0}}.status{--tblr-status-height: 1.5rem;--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145;display:inline-flex;align-items:center;height:var(--tblr-status-height);padding:.25rem .75rem;gap:.5rem;color:var(--tblr-status-color);background:rgba(var(--tblr-status-color-rgb),.1);font-size:.875rem;text-transform:none;letter-spacing:normal;border-radius:100rem;font-weight:var(--tblr-font-weight-medium);line-height:1;margin:0}.status .status-dot{background:var(--tblr-status-color)}.status .icon{font-size:1.25rem}.status-lite{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)!important;background:transparent!important;color:var(--tblr-body-color)!important}.status-primary{--tblr-status-color: #00857D;--tblr-status-color-rgb: 0, 133, 125}.status-secondary{--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145}.status-success{--tblr-status-color: #2fb344;--tblr-status-color-rgb: 47, 179, 68}.status-info{--tblr-status-color: #4299e1;--tblr-status-color-rgb: 66, 153, 225}.status-warning{--tblr-status-color: #f76707;--tblr-status-color-rgb: 247, 103, 7}.status-danger{--tblr-status-color: #d63939;--tblr-status-color-rgb: 214, 57, 57}.status-light{--tblr-status-color: #f6f8fb;--tblr-status-color-rgb: 246, 248, 251}.status-dark{--tblr-status-color: #182433;--tblr-status-color-rgb: 24, 36, 51}.status-muted{--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145}.status-blue{--tblr-status-color: #066fd1;--tblr-status-color-rgb: 6, 111, 209}.status-azure{--tblr-status-color: #4299e1;--tblr-status-color-rgb: 66, 153, 225}.status-indigo{--tblr-status-color: #4263eb;--tblr-status-color-rgb: 66, 99, 235}.status-purple{--tblr-status-color: #ae3ec9;--tblr-status-color-rgb: 174, 62, 201}.status-pink{--tblr-status-color: #d6336c;--tblr-status-color-rgb: 214, 51, 108}.status-red{--tblr-status-color: #d63939;--tblr-status-color-rgb: 214, 57, 57}.status-orange{--tblr-status-color: #f76707;--tblr-status-color-rgb: 247, 103, 7}.status-yellow{--tblr-status-color: #f59f00;--tblr-status-color-rgb: 245, 159, 0}.status-lime{--tblr-status-color: #74b816;--tblr-status-color-rgb: 116, 184, 22}.status-green{--tblr-status-color: #2fb344;--tblr-status-color-rgb: 47, 179, 68}.status-teal{--tblr-status-color: #0ca678;--tblr-status-color-rgb: 12, 166, 120}.status-cyan{--tblr-status-color: #17a2b8;--tblr-status-color-rgb: 23, 162, 184}.status-x{--tblr-status-color: #000000;--tblr-status-color-rgb: 0, 0, 0}.status-facebook{--tblr-status-color: #1877f2;--tblr-status-color-rgb: 24, 119, 242}.status-twitter{--tblr-status-color: #1da1f2;--tblr-status-color-rgb: 29, 161, 242}.status-linkedin{--tblr-status-color: #0a66c2;--tblr-status-color-rgb: 10, 102, 194}.status-google{--tblr-status-color: #dc4e41;--tblr-status-color-rgb: 220, 78, 65}.status-youtube{--tblr-status-color: #ff0000;--tblr-status-color-rgb: 255, 0, 0}.status-vimeo{--tblr-status-color: #1ab7ea;--tblr-status-color-rgb: 26, 183, 234}.status-dribbble{--tblr-status-color: #ea4c89;--tblr-status-color-rgb: 234, 76, 137}.status-github{--tblr-status-color: #181717;--tblr-status-color-rgb: 24, 23, 23}.status-instagram{--tblr-status-color: #e4405f;--tblr-status-color-rgb: 228, 64, 95}.status-pinterest{--tblr-status-color: #bd081c;--tblr-status-color-rgb: 189, 8, 28}.status-vk{--tblr-status-color: #6383a8;--tblr-status-color-rgb: 99, 131, 168}.status-rss{--tblr-status-color: #ffa500;--tblr-status-color-rgb: 255, 165, 0}.status-flickr{--tblr-status-color: #0063dc;--tblr-status-color-rgb: 0, 99, 220}.status-bitbucket{--tblr-status-color: #0052cc;--tblr-status-color-rgb: 0, 82, 204}.status-tabler{--tblr-status-color: #066fd1;--tblr-status-color-rgb: 6, 111, 209}.status-dot{--tblr-status-dot-color: var(--tblr-status-color, #6c7a91);--tblr-status-size: .5rem;position:relative;display:inline-block;width:var(--tblr-status-size);height:var(--tblr-status-size);background:var(--tblr-status-dot-color);border-radius:100rem}.status-dot-animated:before{content:"";position:absolute;inset:0;z-index:0;background:inherit;border-radius:inherit;opacity:.6;animation:1s linear 2s backwards infinite status-pulsate-tertiary}.status-indicator{--tblr-status-indicator-size: 2.5rem;--tblr-status-indicator-color: var(--tblr-status-color, #6c7a91);display:block;position:relative;width:var(--tblr-status-indicator-size);height:var(--tblr-status-indicator-size)}.status-indicator-circle{--tblr-status-circle-size: .75rem;position:absolute;left:50%;top:50%;margin:calc(var(--tblr-status-circle-size) / -2) 0 0 calc(var(--tblr-status-circle-size) / -2);width:var(--tblr-status-circle-size);height:var(--tblr-status-circle-size);border-radius:100rem;background:var(--tblr-status-color)}.status-indicator-circle:nth-child(1){z-index:3}.status-indicator-circle:nth-child(2){z-index:2;opacity:.1}.status-indicator-circle:nth-child(3){z-index:1;opacity:.3}.status-indicator-animated .status-indicator-circle:nth-child(1){animation:2s linear 1s infinite backwards status-pulsate-main}.status-indicator-animated .status-indicator-circle:nth-child(2){animation:2s linear 1s infinite backwards status-pulsate-secondary}.status-indicator-animated .status-indicator-circle:nth-child(3){animation:2s linear 1s infinite backwards status-pulsate-tertiary}.switch-icon{display:inline-block;line-height:1;border:0;padding:0;background:transparent;width:1.25rem;height:1.25rem;vertical-align:bottom;position:relative;cursor:pointer}.switch-icon.disabled{pointer-events:none;opacity:.4}.switch-icon:focus{outline:none}.switch-icon svg{display:block;width:100%;height:100%}.switch-icon .switch-icon-a,.switch-icon .switch-icon-b{display:block;width:100%;height:100%}.switch-icon .switch-icon-a{opacity:1}.switch-icon .switch-icon-b{position:absolute;top:0;left:0;opacity:0}.switch-icon.active .switch-icon-a{opacity:0}.switch-icon.active .switch-icon-b{opacity:1}.switch-icon-fade .switch-icon-a,.switch-icon-fade .switch-icon-b{transition:opacity .5s}@media (prefers-reduced-motion: reduce){.switch-icon-fade .switch-icon-a,.switch-icon-fade .switch-icon-b{transition:none}}.switch-icon-scale .switch-icon-a,.switch-icon-scale .switch-icon-b{transition:opacity .5s,transform 0s .5s}@media (prefers-reduced-motion: reduce){.switch-icon-scale .switch-icon-a,.switch-icon-scale .switch-icon-b{transition:none}}.switch-icon-scale .switch-icon-b{transform:scale(1.5)}.switch-icon-scale.active .switch-icon-a,.switch-icon-scale.active .switch-icon-b{transition:opacity 0s,transform .5s}@media (prefers-reduced-motion: reduce){.switch-icon-scale.active .switch-icon-a,.switch-icon-scale.active .switch-icon-b{transition:none}}.switch-icon-scale.active .switch-icon-b{transform:scale(1)}.switch-icon-flip{perspective:10em}.switch-icon-flip .switch-icon-a,.switch-icon-flip .switch-icon-b{backface-visibility:hidden;transform-style:preserve-3d;transition:opacity 0s .2s,transform .4s ease-in-out}@media (prefers-reduced-motion: reduce){.switch-icon-flip .switch-icon-a,.switch-icon-flip .switch-icon-b{transition:none}}.switch-icon-flip .switch-icon-a{opacity:1;transform:rotateY(0)}.switch-icon-flip .switch-icon-b{opacity:1;transform:rotateY(-180deg)}.switch-icon-flip.active .switch-icon-a{opacity:1;transform:rotateY(180deg)}.switch-icon-flip.active .switch-icon-b{opacity:1;transform:rotateY(0)}.switch-icon-slide-up,.switch-icon-slide-left,.switch-icon-slide-right,.switch-icon-slide-down{overflow:hidden}.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-a,.switch-icon-slide-down .switch-icon-b{transition:opacity .3s,transform .3s}@media (prefers-reduced-motion: reduce){.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-a,.switch-icon-slide-down .switch-icon-b{transition:none}}.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-down .switch-icon-a{transform:translateY(0)}.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-b{transform:translateY(100%)}.switch-icon-slide-up.active .switch-icon-a,.switch-icon-slide-left.active .switch-icon-a,.switch-icon-slide-right.active .switch-icon-a,.switch-icon-slide-down.active .switch-icon-a{transform:translateY(-100%)}.switch-icon-slide-up.active .switch-icon-b,.switch-icon-slide-left.active .switch-icon-b,.switch-icon-slide-right.active .switch-icon-b,.switch-icon-slide-down.active .switch-icon-b{transform:translateY(0)}.switch-icon-slide-left .switch-icon-a{transform:translate(0)}.switch-icon-slide-left .switch-icon-b{transform:translate(100%)}.switch-icon-slide-left.active .switch-icon-a{transform:translate(-100%)}.switch-icon-slide-left.active .switch-icon-b,.switch-icon-slide-right .switch-icon-a{transform:translate(0)}.switch-icon-slide-right .switch-icon-b{transform:translate(-100%)}.switch-icon-slide-right.active .switch-icon-a{transform:translate(100%)}.switch-icon-slide-right.active .switch-icon-b{transform:translate(0)}.switch-icon-slide-down .switch-icon-a{transform:translateY(0)}.switch-icon-slide-down .switch-icon-b{transform:translateY(-100%)}.switch-icon-slide-down.active .switch-icon-a{transform:translateY(100%)}.switch-icon-slide-down.active .switch-icon-b{transform:translateY(0)}.table thead th,.markdown>table thead th{color:var(--tblr-gray-500);background:var(--tblr-bg-surface-tertiary);font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);padding-top:.5rem;padding-bottom:.5rem;white-space:nowrap}@media print{.table thead th,.markdown>table thead th{background:transparent}}.table-responsive .table,.table-responsive .markdown>table{margin-bottom:0}.table-responsive+.card-footer{border-top:0}.table-transparent thead th{background:transparent}.table-nowrap>:not(caption)>*>*{white-space:nowrap}.table-vcenter>:not(caption)>*>*{vertical-align:middle}.table-center>:not(caption)>*>*{text-align:center}.td-truncate{max-width:1px;width:100%}.table-mobile{display:block}.table-mobile thead{display:none}.table-mobile tbody,.table-mobile tr{display:flex;flex-direction:column}.table-mobile td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile .btn{display:block}@media (max-width: 575.98px){.table-mobile-sm{display:block}.table-mobile-sm thead{display:none}.table-mobile-sm tbody,.table-mobile-sm tr{display:flex;flex-direction:column}.table-mobile-sm td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-sm td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-sm tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-sm .btn{display:block}}@media (max-width: 767.98px){.table-mobile-md{display:block}.table-mobile-md thead{display:none}.table-mobile-md tbody,.table-mobile-md tr{display:flex;flex-direction:column}.table-mobile-md td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-md td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-md tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-md .btn{display:block}}@media (max-width: 991.98px){.table-mobile-lg{display:block}.table-mobile-lg thead{display:none}.table-mobile-lg tbody,.table-mobile-lg tr{display:flex;flex-direction:column}.table-mobile-lg td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-lg td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-lg tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-lg .btn{display:block}}@media (max-width: 1199.98px){.table-mobile-xl{display:block}.table-mobile-xl thead{display:none}.table-mobile-xl tbody,.table-mobile-xl tr{display:flex;flex-direction:column}.table-mobile-xl td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-xl td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-xl tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-xl .btn{display:block}}@media (max-width: 1399.98px){.table-mobile-xxl{display:block}.table-mobile-xxl thead{display:none}.table-mobile-xxl tbody,.table-mobile-xxl tr{display:flex;flex-direction:column}.table-mobile-xxl td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-xxl td[data-label]:before{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-xxl tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-xxl .btn{display:block}}.table-sort{font:inherit;color:inherit;text-transform:inherit;letter-spacing:inherit;border:0;background:inherit;display:block;width:100%;text-align:inherit;transition:color .3s;margin:-.5rem;padding:.5rem}@media (prefers-reduced-motion: reduce){.table-sort{transition:none}}.table-sort:hover,.table-sort.asc,.table-sort.desc{color:var(--tblr-body-color)}.table-sort:after{content:"";display:inline-flex;width:1rem;height:1rem;vertical-align:bottom;mask-image:url("data:image/svg+xml,");background:currentColor;margin-left:.25rem}.table-sort.asc:after{mask-image:url("data:image/svg+xml,")}.table-sort.desc:after{mask-image:url("data:image/svg+xml,")}.table-borderless thead th{background:transparent}.tag{--tblr-tag-height: 1.5rem;border:1px solid var(--tblr-border-color);display:inline-flex;align-items:center;height:var(--tblr-tag-height);border-radius:var(--tblr-border-radius);padding:0 .5rem;background:var(--tblr-bg-surface);box-shadow:var(--tblr-box-shadow-input);gap:.5rem}.tag .btn-close{margin-right:-.25rem;margin-left:-.125rem;padding:0;width:1rem;height:1rem;font-size:.5rem}.tag-badge{--tblr-badge-font-size: .625rem;--tblr-badge-padding-x: .25rem;--tblr-badge-padding-y: .125rem;margin-right:-.25rem}.tag-avatar,.tag-flag,.tag-payment,.tag-icon,.tag-check{margin-left:-.25rem}.tag-icon{color:var(--tblr-secondary);margin-right:-.125rem;width:1rem;height:1rem}.tag-check{width:1rem;height:1rem;background-size:1rem}.tags-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.toast{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);box-shadow:#1824330a 0 2px 4px}.toast .toast-header{user-select:none}.toast button[data-bs-dismiss=toast]{outline:none}.toast-primary{--tblr-toast-color: #00857D}.toast-secondary{--tblr-toast-color: #6c7a91}.toast-success{--tblr-toast-color: #2fb344}.toast-info{--tblr-toast-color: #4299e1}.toast-warning{--tblr-toast-color: #f76707}.toast-danger{--tblr-toast-color: #d63939}.toast-light{--tblr-toast-color: #f6f8fb}.toast-dark{--tblr-toast-color: #182433}.toast-muted{--tblr-toast-color: #6c7a91}.toast-blue{--tblr-toast-color: #066fd1}.toast-azure{--tblr-toast-color: #4299e1}.toast-indigo{--tblr-toast-color: #4263eb}.toast-purple{--tblr-toast-color: #ae3ec9}.toast-pink{--tblr-toast-color: #d6336c}.toast-red{--tblr-toast-color: #d63939}.toast-orange{--tblr-toast-color: #f76707}.toast-yellow{--tblr-toast-color: #f59f00}.toast-lime{--tblr-toast-color: #74b816}.toast-green{--tblr-toast-color: #2fb344}.toast-teal{--tblr-toast-color: #0ca678}.toast-cyan{--tblr-toast-color: #17a2b8}.toast-x{--tblr-toast-color: #000000}.toast-facebook{--tblr-toast-color: #1877f2}.toast-twitter{--tblr-toast-color: #1da1f2}.toast-linkedin{--tblr-toast-color: #0a66c2}.toast-google{--tblr-toast-color: #dc4e41}.toast-youtube{--tblr-toast-color: #ff0000}.toast-vimeo{--tblr-toast-color: #1ab7ea}.toast-dribbble{--tblr-toast-color: #ea4c89}.toast-github{--tblr-toast-color: #181717}.toast-instagram{--tblr-toast-color: #e4405f}.toast-pinterest{--tblr-toast-color: #bd081c}.toast-vk{--tblr-toast-color: #6383a8}.toast-rss{--tblr-toast-color: #ffa500}.toast-flickr{--tblr-toast-color: #0063dc}.toast-bitbucket{--tblr-toast-color: #0052cc}.toast-tabler{--tblr-toast-color: #066fd1}.toolbar{display:flex;flex-wrap:nowrap;flex-shrink:0;margin:0 -.5rem}.toolbar>*{margin:0 .5rem}.tracking{--tblr-tracking-height: 1.5rem;--tblr-tracking-gap-width: .125rem;--tblr-tracking-block-border-radius: var(--tblr-border-radius);display:flex;gap:var(--tblr-tracking-gap-width)}.tracking-squares{--tblr-tracking-block-border-radius: var(--tblr-border-radius-sm)}.tracking-squares .tracking-block{height:auto}.tracking-squares .tracking-block:before{content:"";display:block;padding-top:100%}.tracking-block{flex:1;border-radius:var(--tblr-tracking-block-border-radius);height:var(--tblr-tracking-height);min-width:.25rem;background:var(--tblr-border-color)}.timeline{--tblr-timeline-icon-size: 2.5rem;position:relative;list-style:none;padding:0}.timeline-event{position:relative}.timeline-event:not(:last-child){margin-bottom:var(--tblr-page-padding)}.timeline-event:not(:last-child):before{content:"";position:absolute;top:var(--tblr-timeline-icon-size);left:calc(var(--tblr-timeline-icon-size) / 2);bottom:calc(-1 * var(--tblr-page-padding));width:var(--tblr-border-width);background-color:var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.timeline-event-icon{position:absolute;display:flex;align-items:center;justify-content:center;width:var(--tblr-timeline-icon-size, 2.5rem);height:var(--tblr-timeline-icon-size, 2.5rem);background:var(--tblr-gray-200);color:var(--tblr-secondary);border-radius:var(--tblr-border-radius);z-index:5}.timeline-event-card{margin-left:calc(var(--tblr-timeline-icon-size, 2.5rem) + var(--tblr-page-padding))}.timeline-simple .timeline-event-icon{display:none}.timeline-simple .timeline-event-card{margin-left:0}.hr-text{display:flex;align-items:center;margin:2rem 0;font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);height:1px}.hr-text:after,.hr-text:before{flex:1 1 auto;height:1px;background-color:var(--tblr-border-color)}.hr-text:before{content:"";margin-right:.5rem}.hr-text:after{content:"";margin-left:.5rem}.hr-text>*:first-child{padding-right:.5rem;padding-left:0;color:var(--tblr-secondary)}.hr-text.hr-text-left:before{content:none}.hr-text.hr-text-left>*:first-child{padding-right:.5rem;padding-left:.5rem}.hr-text.hr-text-right:before{content:""}.hr-text.hr-text-right:after{content:none}.hr-text.hr-text-right>*:first-child{padding-right:0;padding-left:.5rem}.card>.hr-text{margin:0}.hr-text-spaceless{margin:-.5rem 0}.lead{line-height:1.4}a{text-decoration-skip-ink:auto}h1 a,h2 a,h3 a,.field-group h2 a,h4 a,h5 a,h6 a,.h1 a,.h2 a,.h3 a,.h4 a,.h5 a,.h6 a,h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover,.h1 a:hover,.h2 a:hover,.h3 a:hover,.h4 a:hover,.h5 a:hover,.h6 a:hover{color:inherit}h1,.h1{font-size:var(--tblr-font-size-h1);line-height:var(--tblr-line-height-h1)}h2,.h2{font-size:var(--tblr-font-size-h2);line-height:var(--tblr-line-height-h2)}h3,.field-group h2,.field-group .h2,.h3{font-size:var(--tblr-font-size-h3);line-height:var(--tblr-line-height-h3)}h4,.h4{font-size:var(--tblr-font-size-h4);line-height:var(--tblr-line-height-h4)}h5,.h5{font-size:var(--tblr-font-size-h5);line-height:var(--tblr-line-height-h5)}h6,.h6{font-size:var(--tblr-font-size-h6);line-height:var(--tblr-line-height-h6)}strong,.strong,b{font-weight:var(--tblr-font-weight-bold)}blockquote{padding-left:1rem;border-left:2px var(--tblr-border-style) var(--tblr-border-color)}blockquote p{margin-bottom:1rem}blockquote cite{display:block;text-align:right}blockquote cite:before{content:"\2014 "}ul,ol{padding-left:1.5rem}hr,.hr{margin:2rem 0}dl dd:last-child{margin-bottom:0}pre{padding:1rem;background:var(--tblr-bg-surface-dark);color:var(--tblr-light);border-radius:var(--tblr-border-radius)}pre code{background:transparent}code{background:var(--tblr-code-bg);padding:2px 4px;border-radius:var(--tblr-border-radius)}kbd,.kbd{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);display:inline-block;box-sizing:border-box;max-width:100%;font-size:var(--tblr-font-size-h5);font-weight:var(--tblr-font-weight-medium);line-height:1;vertical-align:baseline;border-radius:var(--tblr-border-radius)}img,svg{max-width:100%;height:auto}.list-unstyled{margin-left:0}::selection{background-color:rgba(var(--tblr-primary-rgb),.16)}[class^=link-].disabled,[class*=" link-"].disabled{color:var(--tblr-disabled-color)!important;pointer-events:none}.subheader{font-size:.625rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary)}.chart{display:block;min-height:10rem}.chart text{font-family:inherit}.chart-sm{height:2.5rem}.chart-lg{height:15rem}.chart-square{height:5.75rem}.chart-sparkline{position:relative;width:4rem;height:2.5rem;line-height:1;min-height:0!important}.chart-sparkline-sm{height:1.5rem}.chart-sparkline-square{width:2.5rem}.chart-sparkline-wide{width:6rem}.chart-sparkline-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:.625rem}.chart-sparkline-label .icon{width:1rem;height:1rem;font-size:1rem}.offcanvas-header{border-bottom:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)}.offcanvas-footer{padding:1.5rem}.offcanvas-title{font-size:1rem;font-weight:var(--tblr-font-weight-medium);line-height:1.5rem}.offcanvas-narrow{width:20rem}.chat-bubbles{display:flex;flex-direction:column;gap:1rem}.chat-bubble{background:var(--tblr-bg-surface-secondary);border-radius:var(--tblr-border-radius-lg);padding:1rem;position:relative}.chat-bubble-me{background-color:var(--tblr-primary-lt);box-shadow:none}.chat-bubble-title{margin-bottom:.25rem}.chat-bubble-author{font-weight:600}.chat-bubble-date{color:var(--tblr-secondary)}.chat-bubble-body>*:last-child{margin-bottom:0}.bg-white-overlay{color:#fff;background-color:#f6f8fb3d}.bg-dark-overlay{color:#fff;background-color:#1824333d}.bg-cover{background-repeat:no-repeat;background-size:cover;background-position:center}.bg-primary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-primary-rgb),var(--tblr-bg-opacity))!important}.bg-primary-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-primary-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-primary-lt-rgb),var(--tblr-bg-opacity))!important}.border-primary{border-color:#00857d!important}.bg-secondary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-secondary-rgb),var(--tblr-bg-opacity))!important}.bg-secondary-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-secondary-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-secondary-lt-rgb),var(--tblr-bg-opacity))!important}.border-secondary{border-color:#6c7a91!important}.bg-success{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-success-rgb),var(--tblr-bg-opacity))!important}.bg-success-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-success-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-success-lt-rgb),var(--tblr-bg-opacity))!important}.border-success{border-color:#2fb344!important}.bg-info{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-info-rgb),var(--tblr-bg-opacity))!important}.bg-info-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-info-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-info-lt-rgb),var(--tblr-bg-opacity))!important}.border-info{border-color:#4299e1!important}.bg-warning{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-warning-rgb),var(--tblr-bg-opacity))!important}.bg-warning-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-warning-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-warning-lt-rgb),var(--tblr-bg-opacity))!important}.border-warning{border-color:#f76707!important}.bg-danger{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-danger-rgb),var(--tblr-bg-opacity))!important}.bg-danger-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-danger-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-danger-lt-rgb),var(--tblr-bg-opacity))!important}.border-danger{border-color:#d63939!important}.bg-light{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-light-rgb),var(--tblr-bg-opacity))!important}.bg-light-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-light-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-light-lt-rgb),var(--tblr-bg-opacity))!important}.border-light{border-color:#f6f8fb!important}.bg-dark{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-dark-rgb),var(--tblr-bg-opacity))!important}.bg-dark-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-dark-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-dark-lt-rgb),var(--tblr-bg-opacity))!important}.border-dark{border-color:#182433!important}.bg-muted{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-muted-rgb),var(--tblr-bg-opacity))!important}.bg-muted-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-muted-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-muted-lt-rgb),var(--tblr-bg-opacity))!important}.border-muted{border-color:#6c7a91!important}.bg-blue{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-blue-rgb),var(--tblr-bg-opacity))!important}.bg-blue-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-blue-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-blue-lt-rgb),var(--tblr-bg-opacity))!important}.border-blue{border-color:#066fd1!important}.bg-azure{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-azure-rgb),var(--tblr-bg-opacity))!important}.bg-azure-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-azure-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-azure-lt-rgb),var(--tblr-bg-opacity))!important}.border-azure{border-color:#4299e1!important}.bg-indigo{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-indigo-rgb),var(--tblr-bg-opacity))!important}.bg-indigo-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-indigo-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-indigo-lt-rgb),var(--tblr-bg-opacity))!important}.border-indigo{border-color:#4263eb!important}.bg-purple{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-purple-rgb),var(--tblr-bg-opacity))!important}.bg-purple-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-purple-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-purple-lt-rgb),var(--tblr-bg-opacity))!important}.border-purple{border-color:#ae3ec9!important}.bg-pink{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-pink-rgb),var(--tblr-bg-opacity))!important}.bg-pink-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-pink-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-pink-lt-rgb),var(--tblr-bg-opacity))!important}.border-pink{border-color:#d6336c!important}.bg-red{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-red-rgb),var(--tblr-bg-opacity))!important}.bg-red-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-red-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-red-lt-rgb),var(--tblr-bg-opacity))!important}.border-red{border-color:#d63939!important}.bg-orange{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-orange-rgb),var(--tblr-bg-opacity))!important}.bg-orange-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-orange-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-orange-lt-rgb),var(--tblr-bg-opacity))!important}.border-orange{border-color:#f76707!important}.bg-yellow{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-yellow-rgb),var(--tblr-bg-opacity))!important}.bg-yellow-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-yellow-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-yellow-lt-rgb),var(--tblr-bg-opacity))!important}.border-yellow{border-color:#f59f00!important}.bg-lime{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-lime-rgb),var(--tblr-bg-opacity))!important}.bg-lime-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-lime-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-lime-lt-rgb),var(--tblr-bg-opacity))!important}.border-lime{border-color:#74b816!important}.bg-green{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-green-rgb),var(--tblr-bg-opacity))!important}.bg-green-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-green-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-green-lt-rgb),var(--tblr-bg-opacity))!important}.border-green{border-color:#2fb344!important}.bg-teal{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-teal-rgb),var(--tblr-bg-opacity))!important}.bg-teal-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-teal-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-teal-lt-rgb),var(--tblr-bg-opacity))!important}.border-teal{border-color:#0ca678!important}.bg-cyan{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-cyan-rgb),var(--tblr-bg-opacity))!important}.bg-cyan-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-cyan-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-cyan-lt-rgb),var(--tblr-bg-opacity))!important}.border-cyan{border-color:#17a2b8!important}.bg-x{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-x-rgb),var(--tblr-bg-opacity))!important}.bg-x-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-x-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-x-lt-rgb),var(--tblr-bg-opacity))!important}.border-x{border-color:#000!important}.bg-facebook{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-facebook-rgb),var(--tblr-bg-opacity))!important}.bg-facebook-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-facebook-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-facebook-lt-rgb),var(--tblr-bg-opacity))!important}.border-facebook{border-color:#1877f2!important}.bg-twitter{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-twitter-rgb),var(--tblr-bg-opacity))!important}.bg-twitter-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-twitter-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-twitter-lt-rgb),var(--tblr-bg-opacity))!important}.border-twitter{border-color:#1da1f2!important}.bg-linkedin{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-bg-opacity))!important}.bg-linkedin-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-linkedin-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-linkedin-lt-rgb),var(--tblr-bg-opacity))!important}.border-linkedin{border-color:#0a66c2!important}.bg-google{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-google-rgb),var(--tblr-bg-opacity))!important}.bg-google-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-google-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-google-lt-rgb),var(--tblr-bg-opacity))!important}.border-google{border-color:#dc4e41!important}.bg-youtube{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-youtube-rgb),var(--tblr-bg-opacity))!important}.bg-youtube-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-youtube-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-youtube-lt-rgb),var(--tblr-bg-opacity))!important}.border-youtube{border-color:red!important}.bg-vimeo{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-bg-opacity))!important}.bg-vimeo-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-vimeo-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-vimeo-lt-rgb),var(--tblr-bg-opacity))!important}.border-vimeo{border-color:#1ab7ea!important}.bg-dribbble{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-bg-opacity))!important}.bg-dribbble-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-dribbble-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-dribbble-lt-rgb),var(--tblr-bg-opacity))!important}.border-dribbble{border-color:#ea4c89!important}.bg-github{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-github-rgb),var(--tblr-bg-opacity))!important}.bg-github-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-github-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-github-lt-rgb),var(--tblr-bg-opacity))!important}.border-github{border-color:#181717!important}.bg-instagram{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-instagram-rgb),var(--tblr-bg-opacity))!important}.bg-instagram-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-instagram-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-instagram-lt-rgb),var(--tblr-bg-opacity))!important}.border-instagram{border-color:#e4405f!important}.bg-pinterest{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-bg-opacity))!important}.bg-pinterest-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-pinterest-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-pinterest-lt-rgb),var(--tblr-bg-opacity))!important}.border-pinterest{border-color:#bd081c!important}.bg-vk{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-vk-rgb),var(--tblr-bg-opacity))!important}.bg-vk-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-vk-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-vk-lt-rgb),var(--tblr-bg-opacity))!important}.border-vk{border-color:#6383a8!important}.bg-rss{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-rss-rgb),var(--tblr-bg-opacity))!important}.bg-rss-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-rss-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-rss-lt-rgb),var(--tblr-bg-opacity))!important}.border-rss{border-color:orange!important}.bg-flickr{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-flickr-rgb),var(--tblr-bg-opacity))!important}.bg-flickr-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-flickr-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-flickr-lt-rgb),var(--tblr-bg-opacity))!important}.border-flickr{border-color:#0063dc!important}.bg-bitbucket{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-bg-opacity))!important}.bg-bitbucket-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-bitbucket-lt-rgb),var(--tblr-bg-opacity))!important}.border-bitbucket{border-color:#0052cc!important}.bg-tabler{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-tabler-rgb),var(--tblr-bg-opacity))!important}.bg-tabler-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-tabler-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-tabler-lt-rgb),var(--tblr-bg-opacity))!important}.border-tabler{border-color:#066fd1!important}.bg-white{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-white-rgb),var(--tblr-bg-opacity))!important}.bg-white-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-white-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-white-lt-rgb),var(--tblr-bg-opacity))!important}.border-white{border-color:#fff!important}.text-primary{--tblr-text-opacity: 1;color:rgba(var(--tblr-primary-rgb),var(--tblr-text-opacity))!important}.text-primary-fg{color:var(--tblr-primary-fg)!important}.text-secondary{--tblr-text-opacity: 1;color:rgba(var(--tblr-secondary-rgb),var(--tblr-text-opacity))!important}.text-secondary-fg{color:var(--tblr-secondary-fg)!important}.text-success{--tblr-text-opacity: 1;color:rgba(var(--tblr-success-rgb),var(--tblr-text-opacity))!important}.text-success-fg{color:var(--tblr-success-fg)!important}.text-info{--tblr-text-opacity: 1;color:rgba(var(--tblr-info-rgb),var(--tblr-text-opacity))!important}.text-info-fg{color:var(--tblr-info-fg)!important}.text-warning{--tblr-text-opacity: 1;color:rgba(var(--tblr-warning-rgb),var(--tblr-text-opacity))!important}.text-warning-fg{color:var(--tblr-warning-fg)!important}.text-danger{--tblr-text-opacity: 1;color:rgba(var(--tblr-danger-rgb),var(--tblr-text-opacity))!important}.text-danger-fg{color:var(--tblr-danger-fg)!important}.text-light{--tblr-text-opacity: 1;color:rgba(var(--tblr-light-rgb),var(--tblr-text-opacity))!important}.text-light-fg{color:var(--tblr-light-fg)!important}.text-dark{--tblr-text-opacity: 1;color:rgba(var(--tblr-dark-rgb),var(--tblr-text-opacity))!important}.text-dark-fg{color:var(--tblr-dark-fg)!important}.text-muted{--tblr-text-opacity: 1;color:rgba(var(--tblr-muted-rgb),var(--tblr-text-opacity))!important}.text-muted-fg{color:var(--tblr-muted-fg)!important}.text-blue{--tblr-text-opacity: 1;color:rgba(var(--tblr-blue-rgb),var(--tblr-text-opacity))!important}.text-blue-fg{color:var(--tblr-blue-fg)!important}.text-azure{--tblr-text-opacity: 1;color:rgba(var(--tblr-azure-rgb),var(--tblr-text-opacity))!important}.text-azure-fg{color:var(--tblr-azure-fg)!important}.text-indigo{--tblr-text-opacity: 1;color:rgba(var(--tblr-indigo-rgb),var(--tblr-text-opacity))!important}.text-indigo-fg{color:var(--tblr-indigo-fg)!important}.text-purple{--tblr-text-opacity: 1;color:rgba(var(--tblr-purple-rgb),var(--tblr-text-opacity))!important}.text-purple-fg{color:var(--tblr-purple-fg)!important}.text-pink{--tblr-text-opacity: 1;color:rgba(var(--tblr-pink-rgb),var(--tblr-text-opacity))!important}.text-pink-fg{color:var(--tblr-pink-fg)!important}.text-red{--tblr-text-opacity: 1;color:rgba(var(--tblr-red-rgb),var(--tblr-text-opacity))!important}.text-red-fg{color:var(--tblr-red-fg)!important}.text-orange{--tblr-text-opacity: 1;color:rgba(var(--tblr-orange-rgb),var(--tblr-text-opacity))!important}.text-orange-fg{color:var(--tblr-orange-fg)!important}.text-yellow{--tblr-text-opacity: 1;color:rgba(var(--tblr-yellow-rgb),var(--tblr-text-opacity))!important}.text-yellow-fg{color:var(--tblr-yellow-fg)!important}.text-lime{--tblr-text-opacity: 1;color:rgba(var(--tblr-lime-rgb),var(--tblr-text-opacity))!important}.text-lime-fg{color:var(--tblr-lime-fg)!important}.text-green{--tblr-text-opacity: 1;color:rgba(var(--tblr-green-rgb),var(--tblr-text-opacity))!important}.text-green-fg{color:var(--tblr-green-fg)!important}.text-teal{--tblr-text-opacity: 1;color:rgba(var(--tblr-teal-rgb),var(--tblr-text-opacity))!important}.text-teal-fg{color:var(--tblr-teal-fg)!important}.text-cyan{--tblr-text-opacity: 1;color:rgba(var(--tblr-cyan-rgb),var(--tblr-text-opacity))!important}.text-cyan-fg{color:var(--tblr-cyan-fg)!important}.text-x{--tblr-text-opacity: 1;color:rgba(var(--tblr-x-rgb),var(--tblr-text-opacity))!important}.text-x-fg{color:var(--tblr-x-fg)!important}.text-facebook{--tblr-text-opacity: 1;color:rgba(var(--tblr-facebook-rgb),var(--tblr-text-opacity))!important}.text-facebook-fg{color:var(--tblr-facebook-fg)!important}.text-twitter{--tblr-text-opacity: 1;color:rgba(var(--tblr-twitter-rgb),var(--tblr-text-opacity))!important}.text-twitter-fg{color:var(--tblr-twitter-fg)!important}.text-linkedin{--tblr-text-opacity: 1;color:rgba(var(--tblr-linkedin-rgb),var(--tblr-text-opacity))!important}.text-linkedin-fg{color:var(--tblr-linkedin-fg)!important}.text-google{--tblr-text-opacity: 1;color:rgba(var(--tblr-google-rgb),var(--tblr-text-opacity))!important}.text-google-fg{color:var(--tblr-google-fg)!important}.text-youtube{--tblr-text-opacity: 1;color:rgba(var(--tblr-youtube-rgb),var(--tblr-text-opacity))!important}.text-youtube-fg{color:var(--tblr-youtube-fg)!important}.text-vimeo{--tblr-text-opacity: 1;color:rgba(var(--tblr-vimeo-rgb),var(--tblr-text-opacity))!important}.text-vimeo-fg{color:var(--tblr-vimeo-fg)!important}.text-dribbble{--tblr-text-opacity: 1;color:rgba(var(--tblr-dribbble-rgb),var(--tblr-text-opacity))!important}.text-dribbble-fg{color:var(--tblr-dribbble-fg)!important}.text-github{--tblr-text-opacity: 1;color:rgba(var(--tblr-github-rgb),var(--tblr-text-opacity))!important}.text-github-fg{color:var(--tblr-github-fg)!important}.text-instagram{--tblr-text-opacity: 1;color:rgba(var(--tblr-instagram-rgb),var(--tblr-text-opacity))!important}.text-instagram-fg{color:var(--tblr-instagram-fg)!important}.text-pinterest{--tblr-text-opacity: 1;color:rgba(var(--tblr-pinterest-rgb),var(--tblr-text-opacity))!important}.text-pinterest-fg{color:var(--tblr-pinterest-fg)!important}.text-vk{--tblr-text-opacity: 1;color:rgba(var(--tblr-vk-rgb),var(--tblr-text-opacity))!important}.text-vk-fg{color:var(--tblr-vk-fg)!important}.text-rss{--tblr-text-opacity: 1;color:rgba(var(--tblr-rss-rgb),var(--tblr-text-opacity))!important}.text-rss-fg{color:var(--tblr-rss-fg)!important}.text-flickr{--tblr-text-opacity: 1;color:rgba(var(--tblr-flickr-rgb),var(--tblr-text-opacity))!important}.text-flickr-fg{color:var(--tblr-flickr-fg)!important}.text-bitbucket{--tblr-text-opacity: 1;color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-text-opacity))!important}.text-bitbucket-fg{color:var(--tblr-bitbucket-fg)!important}.text-tabler{--tblr-text-opacity: 1;color:rgba(var(--tblr-tabler-rgb),var(--tblr-text-opacity))!important}.text-tabler-fg{color:var(--tblr-tabler-fg)!important}.bg-gray-50{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-50-rgb),var(--tblr-bg-opacity))!important}.text-gray-50-fg{color:#182433!important}.bg-gray-100{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-100-rgb),var(--tblr-bg-opacity))!important}.text-gray-100-fg{color:#182433!important}.bg-gray-200{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-200-rgb),var(--tblr-bg-opacity))!important}.text-gray-200-fg{color:#182433!important}.bg-gray-300{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-300-rgb),var(--tblr-bg-opacity))!important}.text-gray-300-fg{color:#f6f8fb!important}.bg-gray-400{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-400-rgb),var(--tblr-bg-opacity))!important}.text-gray-400-fg{color:#f6f8fb!important}.bg-gray-500{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-500-rgb),var(--tblr-bg-opacity))!important}.text-gray-500-fg{color:#f6f8fb!important}.bg-gray-600{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-600-rgb),var(--tblr-bg-opacity))!important}.text-gray-600-fg{color:#f6f8fb!important}.bg-gray-700{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-700-rgb),var(--tblr-bg-opacity))!important}.text-gray-700-fg{color:#f6f8fb!important}.bg-gray-800{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-800-rgb),var(--tblr-bg-opacity))!important}.text-gray-800-fg{color:#f6f8fb!important}.bg-gray-900{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-900-rgb),var(--tblr-bg-opacity))!important}.text-gray-900-fg{color:#f6f8fb!important}.scrollable{overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}.scrollable.hover{overflow-y:hidden}.scrollable.hover>*{margin-top:-1px}.scrollable.hover:hover,.scrollable.hover:focus,.scrollable.hover:active{overflow:visible;overflow-y:auto}.touch .scrollable{overflow-y:auto!important}.scroll-x,.scroll-y{overflow:hidden;-webkit-overflow-scrolling:touch}.scroll-y{overflow-y:auto}.scroll-x{overflow-x:auto}.no-scroll{overflow:hidden}.w-0{width:0!important}.h-0{height:0!important}.w-1{width:.25rem!important}.h-1{height:.25rem!important}.w-2{width:.5rem!important}.h-2{height:.5rem!important}.w-3{width:1rem!important}.h-3{height:1rem!important}.w-4{width:1.5rem!important}.h-4{height:1.5rem!important}.w-5{width:2rem!important}.h-5{height:2rem!important}.w-6{width:3rem!important}.h-6{height:3rem!important}.w-7{width:5rem!important}.h-7{height:5rem!important}.w-8{width:8rem!important}.h-8{height:8rem!important}.w-auto{width:auto!important}.h-auto{height:auto!important}.w-px{width:1px!important}.h-px{height:1px!important}.w-full{width:100%!important}.h-full{height:100%!important}.opacity-0{opacity:0!important}.opacity-5{opacity:.05!important}.opacity-10{opacity:.1!important}.opacity-15{opacity:.15!important}.opacity-20{opacity:.2!important}.opacity-25{opacity:.25!important}.opacity-30{opacity:.3!important}.opacity-35{opacity:.35!important}.opacity-40{opacity:.4!important}.opacity-45{opacity:.45!important}.opacity-50{opacity:.5!important}.opacity-55{opacity:.55!important}.opacity-60{opacity:.6!important}.opacity-65{opacity:.65!important}.opacity-70{opacity:.7!important}.opacity-75{opacity:.75!important}.opacity-80{opacity:.8!important}.opacity-85{opacity:.85!important}.opacity-90{opacity:.9!important}.opacity-95{opacity:.95!important}.opacity-100{opacity:1!important}.hover-shadow-sm:hover{box-shadow:0 .125rem .25rem #00000013!important}.hover-shadow:hover{box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px!important}.hover-shadow-lg:hover{box-shadow:0 1rem 3rem #0000002d!important}.hover-shadow-none:hover{box-shadow:none!important}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.subpixel-antialiased{-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.ts-control{border:1px solid var(--tblr-border-color);padding:.5625rem .75rem;width:100%;overflow:hidden;position:relative;z-index:1;box-sizing:border-box;box-shadow:none;border-radius:var(--tblr-border-radius);display:flex;flex-wrap:wrap}.ts-wrapper.multi.has-items .ts-control{padding:calc(.5625rem - 1px + -0) .75rem calc(.5625rem - 4px + -0)}.full .ts-control{background-color:var(--tblr-bg-forms)}.disabled .ts-control,.disabled .ts-control *{cursor:default!important}.focus .ts-control{box-shadow:none}.ts-control>*{vertical-align:baseline;display:inline-block}.ts-wrapper.multi .ts-control>div{cursor:pointer;margin:0 3px 3px 0;padding:1px 5px;background:#efefef;color:#182433;border:0 solid #dce1e7}.ts-wrapper.multi .ts-control>div.active{background:#00857d;color:#fff;border:0 solid rgba(0,0,0,0)}.ts-wrapper.multi.disabled .ts-control>div,.ts-wrapper.multi.disabled .ts-control>div.active{color:#727272;background:#fff;border:0 solid white}.ts-control>input{flex:1 1 auto;min-width:7rem;display:inline-block!important;padding:0!important;min-height:0!important;max-height:none!important;max-width:100%!important;margin:0!important;text-indent:0!important;border:0 none!important;background:none!important;line-height:inherit!important;user-select:auto!important;box-shadow:none!important}.ts-control>input::-ms-clear{display:none}.ts-control>input:focus{outline:none!important}.has-items .ts-control>input{margin:0 4px!important}.ts-control.rtl{text-align:right}.ts-control.rtl.single .ts-control:after{left:calc(.75rem + 5px);right:auto}.ts-control.rtl .ts-control>input{margin:0 4px 0 -2px!important}.disabled .ts-control{opacity:.5;background-color:var(--tblr-bg-surface-secondary)}.input-hidden .ts-control>input{opacity:0;position:absolute;left:-10000px}.ts-dropdown{position:absolute;top:100%;left:0;width:100%;z-index:10;border:1px solid #d0d0d0;background:#fff;margin:.25rem 0 0;border-top:0 none;box-sizing:border-box;box-shadow:0 1px 3px #0000001a;border-radius:0 0 var(--tblr-border-radius) var(--tblr-border-radius)}.ts-dropdown [data-selectable]{cursor:pointer;overflow:hidden}.ts-dropdown [data-selectable] .highlight{background:#ffed2866;border-radius:1px}.ts-dropdown .option,.ts-dropdown .optgroup-header,.ts-dropdown .no-results,.ts-dropdown .create{padding:3px .75rem}.ts-dropdown .option,.ts-dropdown [data-disabled],.ts-dropdown [data-disabled] [data-selectable].option{cursor:inherit;opacity:.5}.ts-dropdown [data-selectable].option{opacity:1;cursor:pointer}.ts-dropdown .optgroup:first-child .optgroup-header{border-top:0 none}.ts-dropdown .optgroup-header{color:#49566c;background:var(--tblr-bg-surface);cursor:default}.ts-dropdown .active{background-color:rgba(var(--tblr-secondary-rgb),.08);color:inherit}.ts-dropdown .active.create{color:inherit}.ts-dropdown .create{color:#18243380}.ts-dropdown .spinner{display:inline-block;width:30px;height:30px;margin:3px .75rem}.ts-dropdown .spinner:after{content:" ";display:block;width:24px;height:24px;margin:3px;border-radius:50%;border:5px solid #d0d0d0;border-color:#d0d0d0 transparent #d0d0d0 transparent;animation:lds-dual-ring 1.2s linear infinite}@keyframes lds-dual-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ts-dropdown-content{overflow:hidden auto;max-height:200px;scroll-behavior:smooth}.ts-wrapper.plugin-drag_drop .ts-dragging{color:transparent!important}.ts-wrapper.plugin-drag_drop .ts-dragging>*{visibility:hidden!important}.plugin-checkbox_options:not(.rtl) .option input{margin-right:.5rem}.plugin-checkbox_options.rtl .option input{margin-left:.5rem}.plugin-clear_button{--ts-pr-clear-button: 1em}.plugin-clear_button .clear-button{opacity:0;position:absolute;top:50%;transform:translateY(-50%);right:calc(.75rem - 5px);margin-right:0!important;background:transparent!important;transition:opacity .5s;cursor:pointer}.plugin-clear_button.form-select .clear-button,.plugin-clear_button.single .clear-button{right:max(var(--ts-pr-caret),.75rem)}.plugin-clear_button.focus.has-items .clear-button,.plugin-clear_button:not(.disabled):hover.has-items .clear-button{opacity:1}.ts-wrapper .dropdown-header{position:relative;padding:6px .75rem;border-bottom:1px solid #d0d0d0;background:color-mix(#fff,#d0d0d0,85%);border-radius:var(--tblr-border-radius) var(--tblr-border-radius) 0 0}.ts-wrapper .dropdown-header-close{position:absolute;right:.75rem;top:50%;color:#182433;opacity:.4;margin-top:-12px;line-height:20px;font-size:20px!important}.ts-wrapper .dropdown-header-close:hover{color:#000}.plugin-dropdown_input.focus.dropdown-active .ts-control{box-shadow:none;border:1px solid var(--tblr-border-color);box-shadow:var(--tblr-box-shadow-input)}.plugin-dropdown_input .dropdown-input{border:1px solid #d0d0d0;border-width:0 0 1px;display:block;padding:.5625rem .75rem;box-shadow:none;width:100%;background:transparent}.plugin-dropdown_input.focus .ts-dropdown .dropdown-input{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.plugin-dropdown_input .items-placeholder{border:0 none!important;box-shadow:none!important;width:100%}.plugin-dropdown_input.has-items .items-placeholder,.plugin-dropdown_input.dropdown-active .items-placeholder{display:none!important}.ts-wrapper.plugin-input_autogrow.has-items .ts-control>input{min-width:0}.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control>input{flex:none;min-width:4px}.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control>input::placeholder{color:transparent}.ts-dropdown.plugin-optgroup_columns .ts-dropdown-content{display:flex}.ts-dropdown.plugin-optgroup_columns .optgroup{border-right:1px solid #f2f2f2;border-top:0 none;flex-grow:1;flex-basis:0;min-width:0}.ts-dropdown.plugin-optgroup_columns .optgroup:last-child{border-right:0 none}.ts-dropdown.plugin-optgroup_columns .optgroup:before{display:none}.ts-dropdown.plugin-optgroup_columns .optgroup-header{border-top:0 none}.ts-wrapper.plugin-remove_button .item{display:inline-flex;align-items:center}.ts-wrapper.plugin-remove_button .item .remove{color:inherit;text-decoration:none;vertical-align:middle;display:inline-block;padding:0 5px;border-radius:0 2px 2px 0;box-sizing:border-box}.ts-wrapper.plugin-remove_button .item .remove:hover{background:#0000000d}.ts-wrapper.plugin-remove_button.disabled .item .remove:hover{background:none}.ts-wrapper.plugin-remove_button .remove-single{position:absolute;right:0;top:0;font-size:23px}.ts-wrapper.plugin-remove_button:not(.rtl) .item{padding-right:0!important}.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove{border-left:1px solid #dce1e7;margin-left:5px}.ts-wrapper.plugin-remove_button:not(.rtl) .item.active .remove{border-left-color:#0000}.ts-wrapper.plugin-remove_button:not(.rtl).disabled .item .remove{border-left-color:#fff}.ts-wrapper.plugin-remove_button.rtl .item{padding-left:0!important}.ts-wrapper.plugin-remove_button.rtl .item .remove{border-right:1px solid #dce1e7;margin-right:5px}.ts-wrapper.plugin-remove_button.rtl .item.active .remove{border-right-color:#0000}.ts-wrapper.plugin-remove_button.rtl.disabled .item .remove{border-right-color:#fff}:root{--ts-pr-clear-button: 0px;--ts-pr-caret: 0px;--ts-pr-min: .75rem}.ts-wrapper.single .ts-control,.ts-wrapper.single .ts-control input{cursor:pointer}.ts-control:not(.rtl){padding-right:max(var(--ts-pr-min),var(--ts-pr-clear-button) + var(--ts-pr-caret))!important}.ts-control.rtl{padding-left:max(var(--ts-pr-min),var(--ts-pr-clear-button) + var(--ts-pr-caret))!important}.ts-wrapper{position:relative}.ts-dropdown,.ts-control,.ts-control input{color:#182433;font-family:inherit;font-size:inherit;line-height:1.4285714286}.ts-control,.ts-wrapper.single.input-active .ts-control{background:var(--tblr-bg-forms);cursor:text}.ts-hidden-accessible{border:0!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;white-space:nowrap!important}.ts-dropdown,.ts-dropdown.form-control,.ts-dropdown.form-select{height:auto;padding:0;z-index:1000;background:#fff;border:1px solid var(--tblr-border-color-translucent);border-radius:4px;box-shadow:0 6px 12px #0000002d}.ts-dropdown .optgroup-header{font-size:.765625rem;line-height:1.4285714286}.ts-dropdown .optgroup:first-child:before{display:none}.ts-dropdown .optgroup:before{content:" ";display:block;height:0;margin:var(--tblr-spacer-2) 0;overflow:hidden;border-top:1px solid var(--tblr-border-color-translucent);margin-left:-.75rem;margin-right:-.75rem}.ts-dropdown .create{padding-left:.75rem}.ts-dropdown-content{padding:5px 0}.ts-control{box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;display:flex;align-items:center}@media (prefers-reduced-motion: reduce){.ts-control{transition:none}}.focus .ts-control{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.ts-control .item{display:flex;align-items:center}.ts-wrapper.is-invalid,.was-validated .invalid,.was-validated :invalid+.ts-wrapper{border-color:var(--tblr-form-invalid-color)}.ts-wrapper.is-invalid:not(.single),.was-validated .invalid:not(.single),.was-validated :invalid+.ts-wrapper:not(.single){background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-position:right calc(.3571428572em + .28125rem) center;background-size:calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem);background-repeat:no-repeat}.ts-wrapper.is-invalid.single,.was-validated .invalid.single,.was-validated :invalid+.ts-wrapper.single{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem);background-repeat:no-repeat}.ts-wrapper.is-invalid.focus .ts-control,.was-validated .invalid.focus .ts-control,.was-validated :invalid+.ts-wrapper.focus .ts-control{border-color:var(--tblr-form-invalid-color);box-shadow:0 0 0 .25rem rgba(var(--tblr-form-invalid-color),.25)}.ts-wrapper.is-valid,.was-validated .valid,.was-validated :valid+.ts-wrapper{border-color:var(--tblr-form-valid-color)}.ts-wrapper.is-valid:not(.single),.was-validated .valid:not(.single),.was-validated :valid+.ts-wrapper:not(.single){background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-position:right calc(.3571428572em + .28125rem) center;background-size:calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem);background-repeat:no-repeat}.ts-wrapper.is-valid.single,.was-validated .valid.single,.was-validated :valid+.ts-wrapper.single{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .5625rem) calc(.7142857143em + .5625rem);background-repeat:no-repeat}.ts-wrapper.is-valid.focus .ts-control,.was-validated .valid.focus .ts-control,.was-validated :valid+.ts-wrapper.focus .ts-control{border-color:var(--tblr-form-valid-color);box-shadow:0 0 0 .25rem rgba(var(--tblr-form-valid-color),.25)}.ts-wrapper{min-height:calc(1.4285714286em + 1.125rem + calc(var(--tblr-border-width) * 2));display:flex}.input-group-sm>.ts-wrapper,.ts-wrapper.form-select-sm,.ts-wrapper.form-control-sm{min-height:calc(1.4285714286em + .25rem + calc(var(--tblr-border-width) * 2))}.input-group-sm>.ts-wrapper .ts-control,.ts-wrapper.form-select-sm .ts-control,.ts-wrapper.form-control-sm .ts-control{border-radius:var(--tblr-border-radius-sm);font-size:.75rem}.input-group-sm>.ts-wrapper.has-items .ts-control,.ts-wrapper.form-select-sm.has-items .ts-control,.ts-wrapper.form-control-sm.has-items .ts-control{font-size:.75rem;padding-bottom:0}.input-group-sm>.ts-wrapper.multi.has-items .ts-control,.ts-wrapper.form-select-sm.multi.has-items .ts-control,.ts-wrapper.form-control-sm.multi.has-items .ts-control{padding-top:calc((calc(1.4285714286em + .25rem + calc(var(--tblr-border-width) * 2)) - 1.4285714286 * .75rem - 4px) / 2)!important}.ts-wrapper.multi.has-items .ts-control{padding-left:calc(.75rem - 5px);--ts-pr-min: calc(.75rem - 5px) }.ts-wrapper.multi .ts-control>div{border-radius:calc(var(--tblr-border-radius) - 1px)}.input-group-lg>.ts-wrapper,.ts-wrapper.form-control-lg,.ts-wrapper.form-select-lg{min-height:calc(1.4285714286em + 1rem + calc(var(--tblr-border-width) * 2))}.input-group-lg>.ts-wrapper .ts-control,.ts-wrapper.form-control-lg .ts-control,.ts-wrapper.form-select-lg .ts-control{border-radius:var(--tblr-border-radius-lg);font-size:1.25rem}.ts-wrapper:not(.form-control,.form-select){padding:0;border:none;height:auto;box-shadow:none;background:none}.ts-wrapper:not(.form-control,.form-select).single .ts-control{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px}.ts-wrapper.form-select,.ts-wrapper.single{--ts-pr-caret: 2.25rem}.ts-wrapper.form-control,.ts-wrapper.form-select{padding:0!important;height:auto;box-shadow:none;display:flex}.ts-wrapper.form-control .ts-control,.ts-wrapper.form-control.single.input-active .ts-control,.ts-wrapper.form-select .ts-control,.ts-wrapper.form-select.single.input-active .ts-control{border:none!important}.ts-wrapper.form-control:not(.disabled) .ts-control,.ts-wrapper.form-control:not(.disabled).single.input-active .ts-control,.ts-wrapper.form-select:not(.disabled) .ts-control,.ts-wrapper.form-select:not(.disabled).single.input-active .ts-control{background:transparent!important}.input-group>.ts-wrapper{flex-grow:1;width:1%}.input-group>.ts-wrapper:not(:nth-child(2))>.ts-control{border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.ts-wrapper:not(:last-child)>.ts-control{border-top-right-radius:0;border-bottom-right-radius:0}:root{--ts-pr-clear-button: 0rem;--ts-pr-caret: 0rem}.ts-input,.ts-control{color:inherit}.ts-control .dropdown-menu{width:100%;height:auto}.ts-wrapper .form-control,.ts-wrapper .form-select,.ts-wrapper.form-control,.ts-wrapper.form-select{box-shadow:var(--tblr-box-shadow-input)}.ts-wrapper.is-invalid .ts-control,.ts-wrapper.is-valid .ts-control{--ts-pr-clear-button: 1.5rem}.ts-dropdown{background:var(--tblr-bg-surface);color:var(--tblr-body-color);box-shadow:var(--tblr-box-shadow-dropdown)}.ts-dropdown .option{padding:.5rem .75rem}.ts-control,.ts-control input{color:var(--tblr-body-color)}.ts-control input::placeholder{color:#8a97ab}.ts-wrapper.multi .ts-control>div{background:var(--tblr-bg-surface-secondary);border:1px solid var(--tblr-border-color);color:var(--tblr-body-color)}html{scroll-behavior:auto!important}.table-responsive .dropdown,.table-responsive .btn-group,.table-responsive .btn-group-vertical{position:static}.progress{min-width:80px}hr.dropdown-divider,.dropdown-divider.hr{margin-bottom:.25rem;margin-top:.25rem}.dropdown-item{font-weight:400}*{font-feature-settings:"liga" 0;font-variant-ligatures:none}pre{background-color:transparent;color:inherit}.alert{background:var(--tblr-bg-surface)}.btn{display:inline-block}.btn:focus{border:1px solid var(--tblr-primary-fg);outline:2px solid var(--tblr-primary)!important}.btn-sm,.btn-group-sm>.btn{border-radius:4px}.dropdown-item{display:inline-block}.footer .text-primary{color:#001423!important}.nav-tabs .nav-link{display:inline-block}.page,.page-tabs .nav-tabs .nav-link.active{background-color:var(--tblr-bg-surface-tertiary)!important}.page-body .card .card-header{background:var(--tblr-bg-surface-secondary)!important}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-alert-color: darken(var(--tblr-warning),10%);--tblr-link-color: #00F2D4;--tblr-link-color-rgb: 0,242,212;--tblr-link-hover-color-rgb: 0,242,212;--tblr-secondary: #8a97ab;--tblr-primary: #00F2D4;--tblr-primary-fg: #001423;--tblr-primary-rgb: 0,242,212;--tblr-btn-active-color: #001423}body[data-bs-theme=dark],body[data-bs-theme=dark] body[data-bs-theme=light]{background-color:#001423}body[data-bs-theme=dark] ::selection,body[data-bs-theme=dark] body[data-bs-theme=light] ::selection{background-color:rgba(var(--tblr-primary-rgb),.48)}body[data-bs-theme=dark] .btn-primary,body[data-bs-theme=dark] .bg-primary .card-title,body[data-bs-theme=dark] .bg-primary a,body[data-bs-theme=dark] .bg-primary i,body[data-bs-theme=dark] .text-bg-primary{color:#001423!important}body[data-bs-theme=dark] .card{background:#001423!important}body[data-bs-theme=dark] .navbar,body[data-bs-theme=dark] .page-header{background-color:#001423}body[data-bs-theme=dark] .page,body[data-bs-theme=dark] .page-tabs .nav-tabs .nav-link.active{background-color:#081b2a!important}body[data-bs-theme=dark] .page-link.active,body[data-bs-theme=dark] .active>.page-link{color:#001423}body[data-bs-theme=dark] .text-bg-primary{color:#001423!important}body[data-bs-theme=dark] .text-muted{color:var(--tblr-secondary-color)!important}body[data-bs-theme=dark] .text-secondary{color:#8a97ab!important}body[data-bs-theme=dark] .footer .text-primary{color:#fff!important}body[data-bs-theme=dark] .toast{color:var(--tblr-body-color)}body[data-bs-theme=dark] .table-primary{--tblr-table-bg: rgba(var(--tblr-secondary-rgb), .48);--tblr-table-hover-bg: inherit;--tblr-table-hover-color: inherit}pre code{padding:unset}.dropdown-toggle:after{font-family:Material Design Icons;content:"\f0140";padding-right:9px;border-bottom:none;border-left:none;transform:none;vertical-align:.05em;height:auto}.ts-wrapper.multi .ts-control{padding:7px 7px 3px}.ts-wrapper.multi .ts-control div{margin:0 4px 4px 0}.badge a{color:inherit;text-decoration:none}.page-body .card{margin-bottom:1rem}.page-body .card .card-header,.page-body .card .card-body,.page-body .card .card-footer{padding:.75rem}.page-body .card .card-header{background:var(--tblr-bg-surface-tertiary)}.page-body .card h2.card-header,.page-body .card .card-header.h2{font-size:var(--tblr-font-size-h5);line-height:var(--tblr-line-height-h5);margin-bottom:0}.page-body .card .list-group-item{padding:.5rem .75rem}.page-body .card .table,.page-body .card .markdown>table{margin-bottom:0}form.object-edit{margin:auto;max-width:800px}.col-form-label.required{font-weight:700}.col-form-label.required:after{position:absolute;display:inline-block;margin-left:0;font-family:Material Design Icons;font-size:8px;content:"\f06c4"}.has-errors input,.has-errors select,.has-errors textarea{border:1px solid #d63939}.page{background-color:var(--tblr-bg-surface-secondary)}.page-header{background-color:var(--tblr-bg-surface);min-height:0}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg{padding-bottom:2rem}}.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-link-icon{color:var(--tblr-nav-link-color)!important}.navbar-vertical.navbar-expand-lg .navbar-collapse .text-secondary{color:#00857d!important}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item a{color:#001423}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item .btn-group{visibility:hidden}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover{background-color:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover a{text-decoration:none}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover .btn-group{visibility:visible}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active{background-color:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active a{color:#001423}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active .btn-group{visibility:visible}.navbar-vertical.navbar-expand-lg .navbar-nav{z-index:1}@media (max-width: 991.98px){.navbar-vertical.navbar-expand-lg .navbar-brand{padding:.2rem 0}}.navbar-vertical.navbar-expand-lg .navbar-brand a:hover{text-decoration:none}.navbar-vertical.navbar-expand-lg img.motif{bottom:0;display:none;left:0;mask-image:linear-gradient(180deg,#0000,#0000004d);opacity:.5;position:fixed;user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-drag:none;-webkit-user-select:none;-ms-user-select:none;width:18rem}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg img.motif{display:block}}body[data-bs-theme=light] .navbar-vertical.navbar-expand-lg{background:linear-gradient(180deg,#00857d00,#00857d1a),#fff}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg{background:linear-gradient(180deg,#00f2d400,#00f2d41a),#001423}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .nav-item.dropdown.active:after{border-color:#00f2d4!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item a{color:#fff!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item.active{background-color:#ffffff0f!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item.active a{color:#fff!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item:hover{background-color:#ffffff0f!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item .nav-link-title{color:#fff!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .text-secondary{color:#00f2d4!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg img.motif{opacity:.25}.progress{height:20px}.progress .progress-label{display:flex;flex-direction:column;justify-content:center;padding-left:.25rem}table.object-list tbody>tr:last-child>td{border-bottom-width:0}table.object-list th.asc>a:after{content:"\f0140";font-family:Material Design Icons}table.object-list th.desc>a:after{content:"\f0143";font-family:Material Design Icons}table.attr-table th{font-weight:400;width:min-content}table.attr-table th,table.attr-table td{border-bottom-style:dashed}table.attr-table tr:last-child{border-bottom-style:hidden}table.attr-table td{overflow-wrap:anywhere}td pre{margin-bottom:0}table th.orderable a{color:var(--tblr-body-color)}body[data-bs-theme=dark] .table thead th,body[data-bs-theme=dark] .markdown>table thead th{background:#001423!important}.page-tabs{border-bottom:1px solid var(--tblr-border-color-translucent)}.page-tabs .nav-tabs{position:relative;border:none}.page-tabs .nav-tabs .nav-link.active,.page-tabs .nav-tabs .nav-link:active,.page-tabs .nav-tabs .nav-link:hover{border-color:var(--tblr-border-color-translucent);border-bottom-color:transparent}.page-tabs .nav-tabs .nav-link.active{color:inherit;background:var(--tblr-bg-surface-secondary);border-bottom-color:transparent}pre.change-data{border-radius:0;padding:0}pre.change-data>span{display:block;padding-right:1rem;padding-left:1rem}pre.change-data>span.added{background-color:#2fb344}pre.change-data>span.removed{background-color:#d63939}pre.change-diff{border-color:transparent}pre.change-diff.change-added{background-color:#2fb344}pre.change-diff.change-removed{background-color:#d63939}pre.block{padding:1rem;border:1px solid #dce1e7;border-radius:4px}.grid-stack .card-header.bg-default{background:var(--tblr-bg-surface-secondary)!important}.grid-stack .card-header a{color:inherit!important}tr[data-cable-status=connected]{background-color:#2fb34426}tr[data-cable-status=planned]{background-color:#066fd126}tr[data-cable-status=decommissioning]{background-color:#f59f0026}tr[data-mark-connected=true]{background-color:#2fb34426}tr[data-virtual=true]{background-color:#00857d26}tr[data-enabled=disabled]{background-color:#8a97ab26}tr[data-cable-status=connected] button.mark-installed{display:none}tr:not([data-cable-status=connected]) button.mark-planned{display:none}.rendered-markdown table{width:100%}.rendered-markdown table th{border-bottom:2px solid #dddddd;padding:8px}.rendered-markdown table td{border-top:1px solid #dddddd;padding:8px}.rendered-markdown table th[align=left]{text-align:left}.rendered-markdown table th[align=center]{text-align:center}.rendered-markdown table th[align=right]{text-align:right}.rendered-markdown p:last-of-type{margin-bottom:0}td>.rendered-markdown{max-height:200px;overflow-y:scroll}.markdown-widget .preview{border:1px solid #dce1e7;border-radius:4px;min-height:200px}span.color-label{display:inline-block;width:5rem;height:1rem;padding:.25em .5em;border:1px solid #303030;border-radius:4px}.record-depth{display:inline;user-select:none;opacity:33%}.record-depth span:only-of-type,.record-depth span:last-of-type{margin-right:.25rem}.hide-last-child :last-child{visibility:hidden;opacity:0}.netbox-edition{letter-spacing:.15rem}.btn-float-group,.btn-float-group-right,.btn-float-group-left{position:sticky;bottom:10px;z-index:2}.btn-float-group-left{float:left}.btn-float-group-right{float:right}.btn-float{--tblr-btn-bg: var(--tblr-bg-surface-tertiary) !important}.logo{height:80px}.sso-icon{height:24px}tr[data-read=True] td{background-color:var(--tblr-bg-surface-secondary);color:var(--tblr-secondary-color)} +@charset "UTF-8";:root,[data-bs-theme=light]{--tblr-black: #000000;--tblr-white: #ffffff;--tblr-gray: #49566c;--tblr-gray-dark: #182433;--tblr-gray-100: #eef3f6;--tblr-gray-200: #dce1e7;--tblr-gray-300: #b8c4d4;--tblr-gray-400: #8a97ab;--tblr-gray-500: #6c7a91;--tblr-gray-600: #49566c;--tblr-gray-700: #3a4859;--tblr-gray-800: #182433;--tblr-gray-900: #040a11;--tblr-primary: #00857D;--tblr-secondary: #6c7a91;--tblr-success: #2fb344;--tblr-info: #4299e1;--tblr-warning: #f76707;--tblr-danger: #d63939;--tblr-light: #f6f8fb;--tblr-dark: #182433;--tblr-muted: #6c7a91;--tblr-blue: #066fd1;--tblr-azure: #4299e1;--tblr-indigo: #4263eb;--tblr-purple: #ae3ec9;--tblr-pink: #d6336c;--tblr-red: #d63939;--tblr-orange: #f76707;--tblr-yellow: #f59f00;--tblr-lime: #74b816;--tblr-green: #2fb344;--tblr-teal: #0ca678;--tblr-cyan: #17a2b8;--tblr-x: #000000;--tblr-facebook: #1877f2;--tblr-twitter: #1da1f2;--tblr-linkedin: #0a66c2;--tblr-google: #dc4e41;--tblr-youtube: #ff0000;--tblr-vimeo: #1ab7ea;--tblr-dribbble: #ea4c89;--tblr-github: #181717;--tblr-instagram: #e4405f;--tblr-pinterest: #bd081c;--tblr-vk: #6383a8;--tblr-rss: #ffa500;--tblr-flickr: #0063dc;--tblr-bitbucket: #0052cc;--tblr-tabler: #066fd1;--tblr-primary-rgb: 0, 133, 125;--tblr-secondary-rgb: 108, 122, 145;--tblr-success-rgb: 47, 179, 68;--tblr-info-rgb: 66, 153, 225;--tblr-warning-rgb: 247, 103, 7;--tblr-danger-rgb: 214, 57, 57;--tblr-light-rgb: 246, 248, 251;--tblr-dark-rgb: 24, 36, 51;--tblr-muted-rgb: 108, 122, 145;--tblr-blue-rgb: 6, 111, 209;--tblr-azure-rgb: 66, 153, 225;--tblr-indigo-rgb: 66, 99, 235;--tblr-purple-rgb: 174, 62, 201;--tblr-pink-rgb: 214, 51, 108;--tblr-red-rgb: 214, 57, 57;--tblr-orange-rgb: 247, 103, 7;--tblr-yellow-rgb: 245, 159, 0;--tblr-lime-rgb: 116, 184, 22;--tblr-green-rgb: 47, 179, 68;--tblr-teal-rgb: 12, 166, 120;--tblr-cyan-rgb: 23, 162, 184;--tblr-x-rgb: 0, 0, 0;--tblr-facebook-rgb: 24, 119, 242;--tblr-twitter-rgb: 29, 161, 242;--tblr-linkedin-rgb: 10, 102, 194;--tblr-google-rgb: 220, 78, 65;--tblr-youtube-rgb: 255, 0, 0;--tblr-vimeo-rgb: 26, 183, 234;--tblr-dribbble-rgb: 234, 76, 137;--tblr-github-rgb: 24, 23, 23;--tblr-instagram-rgb: 228, 64, 95;--tblr-pinterest-rgb: 189, 8, 28;--tblr-vk-rgb: 99, 131, 168;--tblr-rss-rgb: 255, 165, 0;--tblr-flickr-rgb: 0, 99, 220;--tblr-bitbucket-rgb: 0, 82, 204;--tblr-tabler-rgb: 6, 111, 209;--tblr-primary-text-emphasis: #003532;--tblr-secondary-text-emphasis: #2b313a;--tblr-success-text-emphasis: #13481b;--tblr-info-text-emphasis: #1a3d5a;--tblr-warning-text-emphasis: #632903;--tblr-danger-text-emphasis: #561717;--tblr-light-text-emphasis: #3a4859;--tblr-dark-text-emphasis: #3a4859;--tblr-primary-bg-subtle: #cce7e5;--tblr-secondary-bg-subtle: #e2e4e9;--tblr-success-bg-subtle: #d5f0da;--tblr-info-bg-subtle: #d9ebf9;--tblr-warning-bg-subtle: #fde1cd;--tblr-danger-bg-subtle: #f7d7d7;--tblr-light-bg-subtle: #f7f9fb;--tblr-dark-bg-subtle: #8a97ab;--tblr-primary-border-subtle: #99cecb;--tblr-secondary-border-subtle: #c4cad3;--tblr-success-border-subtle: #ace1b4;--tblr-info-border-subtle: #b3d6f3;--tblr-warning-border-subtle: #fcc29c;--tblr-danger-border-subtle: #efb0b0;--tblr-light-border-subtle: #dce1e7;--tblr-dark-border-subtle: #6c7a91;--tblr-white-rgb: 255, 255, 255;--tblr-black-rgb: 0, 0, 0;--tblr-font-sans-serif: "Inter", system-ui, sans-serif;--tblr-font-monospace: "Roboto Mono";--tblr-gradient: linear-gradient(180deg, rgba(255, 255, 255, .15), rgba(255, 255, 255, 0));--tblr-body-font-family: var(--tblr-font-sans-serif);--tblr-body-font-size: .875rem;--tblr-body-font-weight: 400;--tblr-body-line-height: 1.4285714286;--tblr-body-color: #182433;--tblr-body-color-rgb: 24, 36, 51;--tblr-body-bg: #f6f8fb;--tblr-body-bg-rgb: 246, 248, 251;--tblr-emphasis-color: #3a4859;--tblr-emphasis-color-rgb: 58, 72, 89;--tblr-secondary-color: rgba(24, 36, 51, .75);--tblr-secondary-color-rgb: 24, 36, 51;--tblr-secondary-bg: #dce1e7;--tblr-secondary-bg-rgb: 220, 225, 231;--tblr-tertiary-color: rgba(24, 36, 51, .5);--tblr-tertiary-color-rgb: 24, 36, 51;--tblr-tertiary-bg: #eef3f6;--tblr-tertiary-bg-rgb: 238, 243, 246;--tblr-heading-color: inherit;--tblr-link-color: #00857D;--tblr-link-color-rgb: 0, 133, 125;--tblr-link-decoration: none;--tblr-link-hover-color: #006a64;--tblr-link-hover-color-rgb: 0, 106, 100;--tblr-link-hover-decoration: underline;--tblr-code-color: var(--tblr-gray-600);--tblr-highlight-color: #182433;--tblr-highlight-bg: #fdeccc;--tblr-border-width: 1px;--tblr-border-style: solid;--tblr-border-color: #dce1e7;--tblr-border-color-translucent: rgba(4, 32, 69, .1);--tblr-border-radius: 4px;--tblr-border-radius-sm: 2px;--tblr-border-radius-lg: 8px;--tblr-border-radius-xl: 1rem;--tblr-border-radius-xxl: 2rem;--tblr-border-radius-2xl: var(--tblr-border-radius-xxl);--tblr-border-radius-pill: 100rem;--tblr-box-shadow: rgba(var(--tblr-body-color-rgb), .04) 0 2px 4px 0;--tblr-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--tblr-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--tblr-box-shadow-inset: 0 0 transparent;--tblr-focus-ring-width: .25rem;--tblr-focus-ring-opacity: .25;--tblr-focus-ring-color: rgba(var(--tblr-primary-rgb), .25);--tblr-form-valid-color: #2fb344;--tblr-form-valid-border-color: #2fb344;--tblr-form-invalid-color: #d63939;--tblr-form-invalid-border-color: #d63939}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{color-scheme:dark;--tblr-body-color: #dce1e7;--tblr-body-color-rgb: 220, 225, 231;--tblr-body-bg: #040a11;--tblr-body-bg-rgb: 4, 10, 17;--tblr-emphasis-color: #ffffff;--tblr-emphasis-color-rgb: 255, 255, 255;--tblr-secondary-color: rgba(220, 225, 231, .75);--tblr-secondary-color-rgb: 220, 225, 231;--tblr-secondary-bg: #182433;--tblr-secondary-bg-rgb: 24, 36, 51;--tblr-tertiary-color: rgba(220, 225, 231, .5);--tblr-tertiary-color-rgb: 220, 225, 231;--tblr-tertiary-bg: #0e1722;--tblr-tertiary-bg-rgb: 14, 23, 34;--tblr-primary-text-emphasis: #66b6b1;--tblr-secondary-text-emphasis: #a7afbd;--tblr-success-text-emphasis: #82d18f;--tblr-info-text-emphasis: #8ec2ed;--tblr-warning-text-emphasis: #faa46a;--tblr-danger-text-emphasis: #e68888;--tblr-light-text-emphasis: #eef3f6;--tblr-dark-text-emphasis: #b8c4d4;--tblr-primary-bg-subtle: #001b19;--tblr-secondary-bg-subtle: #16181d;--tblr-success-bg-subtle: #09240e;--tblr-info-bg-subtle: #0d1f2d;--tblr-warning-bg-subtle: #311501;--tblr-danger-bg-subtle: #2b0b0b;--tblr-light-bg-subtle: #182433;--tblr-dark-bg-subtle: #0c121a;--tblr-primary-border-subtle: #00504b;--tblr-secondary-border-subtle: #414957;--tblr-success-border-subtle: #1c6b29;--tblr-info-border-subtle: #285c87;--tblr-warning-border-subtle: #943e04;--tblr-danger-border-subtle: #802222;--tblr-light-border-subtle: #3a4859;--tblr-dark-border-subtle: #182433;--tblr-heading-color: inherit;--tblr-link-color: #66b6b1;--tblr-link-hover-color: #85c5c1;--tblr-link-color-rgb: 102, 182, 177;--tblr-link-hover-color-rgb: 133, 197, 193;--tblr-code-color: var(--tblr-gray-300);--tblr-highlight-color: #dce1e7;--tblr-highlight-bg: #624000;--tblr-border-color: #25384f;--tblr-border-color-translucent: rgba(72, 110, 149, .14);--tblr-form-valid-color: #82d18f;--tblr-form-valid-border-color: #82d18f;--tblr-form-invalid-color: #e68888;--tblr-form-invalid-border-color: #e68888}*,*:before,*:after{box-sizing:border-box}@media (prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--tblr-body-font-family);font-size:var(--tblr-body-font-size);font-weight:var(--tblr-body-font-weight);line-height:var(--tblr-body-line-height);color:var(--tblr-body-color);text-align:var(--tblr-body-text-align);background-color:var(--tblr-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr,.hr{margin:2rem 0;color:inherit;border:0;border-top:var(--tblr-border-width) solid;opacity:.16}h6,.h6,h5,.h5,h4,.h4,h3,.field-group h2,.field-group .h2,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:var(--tblr-spacer);font-weight:var(--tblr-font-weight-bold);line-height:1.2;color:var(--tblr-heading-color)}h1,.h1{font-size:1.5rem}h2,.h2{font-size:1.25rem}h3,.field-group h2,.field-group .h2,.h3{font-size:1rem}h4,.h4{font-size:.875rem}h5,.h5{font-size:.75rem}h6,.h6{font-size:.625rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;cursor:help;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:600}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:85.714285%}mark,.mark{padding:.1875em;color:var(--tblr-highlight-color);background-color:var(--tblr-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-opacity, 1));text-decoration:none}a:hover{--tblr-link-color-rgb: var(--tblr-link-hover-color-rgb);text-decoration:underline}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--tblr-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:85.714285%;color:var(--tblr-light)}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:85.714285%;color:var(--tblr-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.25rem .5rem;font-size:var(--tblr-font-size-h5);color:var(--tblr-text-secondary-dark);background-color:var(--tblr-code-bg);border-radius:2px}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--tblr-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}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]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:.875rem;font-weight:var(--tblr-font-weight-normal)}.display-1{font-size:5rem;font-weight:300;line-height:1.2}.display-2{font-size:4.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}.display-5{font-size:3rem;font-weight:300;line-height:1.2}.display-6{font-size:2rem;font-weight:300;line-height:1.2}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:85.714285%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:.875rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:85.714285%;color:#49566c}.blockquote-footer:before{content:"\2014\a0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--tblr-body-bg);border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-sm);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:85.714285%;color:var(--tblr-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width: 576px){.container-sm,.container{max-width:540px}}@media (min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media (min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media (min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media (min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--tblr-breakpoint-xs: 0;--tblr-breakpoint-sm: 576px;--tblr-breakpoint-md: 768px;--tblr-breakpoint-lg: 992px;--tblr-breakpoint-xl: 1200px;--tblr-breakpoint-xxl: 1400px}.row{--tblr-gutter-x: var(--tblr-page-padding);--tblr-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--tblr-gutter-y));margin-right:calc(-.5 * var(--tblr-gutter-x));margin-left:calc(-.5 * var(--tblr-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-top:var(--tblr-gutter-y)}.grid{display:grid;grid-template-rows:repeat(var(--tblr-rows, 1),1fr);grid-template-columns:repeat(var(--tblr-columns, 12),1fr);gap:var(--tblr-gap, var(--tblr-page-padding))}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media (min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media (min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media (min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media (min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media (min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-0,.gy-0{--tblr-gutter-y: 0}.g-1,.gx-1{--tblr-gutter-x: .25rem}.g-1,.gy-1{--tblr-gutter-y: .25rem}.g-2,.gx-2{--tblr-gutter-x: .5rem}.g-2,.gy-2{--tblr-gutter-y: .5rem}.g-3,.gx-3{--tblr-gutter-x: 1rem}.g-3,.gy-3{--tblr-gutter-y: 1rem}.g-4,.gx-4{--tblr-gutter-x: 1.5rem}.g-4,.gy-4{--tblr-gutter-y: 1.5rem}.g-5,.gx-5{--tblr-gutter-x: 2rem}.g-5,.gy-5{--tblr-gutter-y: 2rem}.g-6,.gx-6{--tblr-gutter-x: 2.5rem}.g-6,.gy-6{--tblr-gutter-y: 2.5rem}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-sm-0,.gy-sm-0{--tblr-gutter-y: 0}.g-sm-1,.gx-sm-1{--tblr-gutter-x: .25rem}.g-sm-1,.gy-sm-1{--tblr-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--tblr-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--tblr-gutter-y: .5rem}.g-sm-3,.gx-sm-3{--tblr-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--tblr-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--tblr-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--tblr-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--tblr-gutter-x: 2rem}.g-sm-5,.gy-sm-5{--tblr-gutter-y: 2rem}.g-sm-6,.gx-sm-6{--tblr-gutter-x: 2.5rem}.g-sm-6,.gy-sm-6{--tblr-gutter-y: 2.5rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-md-0,.gy-md-0{--tblr-gutter-y: 0}.g-md-1,.gx-md-1{--tblr-gutter-x: .25rem}.g-md-1,.gy-md-1{--tblr-gutter-y: .25rem}.g-md-2,.gx-md-2{--tblr-gutter-x: .5rem}.g-md-2,.gy-md-2{--tblr-gutter-y: .5rem}.g-md-3,.gx-md-3{--tblr-gutter-x: 1rem}.g-md-3,.gy-md-3{--tblr-gutter-y: 1rem}.g-md-4,.gx-md-4{--tblr-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--tblr-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--tblr-gutter-x: 2rem}.g-md-5,.gy-md-5{--tblr-gutter-y: 2rem}.g-md-6,.gx-md-6{--tblr-gutter-x: 2.5rem}.g-md-6,.gy-md-6{--tblr-gutter-y: 2.5rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-lg-0,.gy-lg-0{--tblr-gutter-y: 0}.g-lg-1,.gx-lg-1{--tblr-gutter-x: .25rem}.g-lg-1,.gy-lg-1{--tblr-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--tblr-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--tblr-gutter-y: .5rem}.g-lg-3,.gx-lg-3{--tblr-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--tblr-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--tblr-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--tblr-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--tblr-gutter-x: 2rem}.g-lg-5,.gy-lg-5{--tblr-gutter-y: 2rem}.g-lg-6,.gx-lg-6{--tblr-gutter-x: 2.5rem}.g-lg-6,.gy-lg-6{--tblr-gutter-y: 2.5rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-xl-0,.gy-xl-0{--tblr-gutter-y: 0}.g-xl-1,.gx-xl-1{--tblr-gutter-x: .25rem}.g-xl-1,.gy-xl-1{--tblr-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--tblr-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--tblr-gutter-y: .5rem}.g-xl-3,.gx-xl-3{--tblr-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--tblr-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--tblr-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--tblr-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--tblr-gutter-x: 2rem}.g-xl-5,.gy-xl-5{--tblr-gutter-y: 2rem}.g-xl-6,.gx-xl-6{--tblr-gutter-x: 2.5rem}.g-xl-6,.gy-xl-6{--tblr-gutter-y: 2.5rem}}@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.33333333%}.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.66666667%}.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{--tblr-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--tblr-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--tblr-gutter-x: .25rem}.g-xxl-1,.gy-xxl-1{--tblr-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--tblr-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--tblr-gutter-y: .5rem}.g-xxl-3,.gx-xxl-3{--tblr-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--tblr-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--tblr-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--tblr-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--tblr-gutter-x: 2rem}.g-xxl-5,.gy-xxl-5{--tblr-gutter-y: 2rem}.g-xxl-6,.gx-xxl-6{--tblr-gutter-x: 2.5rem}.g-xxl-6,.gy-xxl-6{--tblr-gutter-y: 2.5rem}}.table,.markdown>table{--tblr-table-color-type: initial;--tblr-table-bg-type: initial;--tblr-table-color-state: initial;--tblr-table-bg-state: initial;--tblr-table-color: inherit;--tblr-table-bg: transparent;--tblr-table-border-color: var(--tblr-border-color-translucent);--tblr-table-accent-bg: transparent;--tblr-table-striped-color: inherit;--tblr-table-striped-bg: var(--tblr-bg-surface-tertiary);--tblr-table-active-color: inherit;--tblr-table-active-bg: rgba(var(--tblr-emphasis-color-rgb), .1);--tblr-table-hover-color: inherit;--tblr-table-hover-bg: rgba(var(--tblr-emphasis-color-rgb), .075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--tblr-table-border-color)}.table>:not(caption)>*>*,.markdown>table>:not(caption)>*>*{padding:.5rem;color:var(--tblr-table-color-state, var(--tblr-table-color-type, var(--tblr-table-color)));background-color:var(--tblr-table-bg);border-bottom-width:var(--tblr-border-width);box-shadow:inset 0 0 0 9999px var(--tblr-table-bg-state, var(--tblr-table-bg-type, var(--tblr-table-accent-bg)))}.table>tbody,.markdown>table>tbody{vertical-align:inherit}.table>thead,.markdown>table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--tblr-border-width) * 2) solid var(--tblr-border-color-translucent)}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*,.markdown>table>:not(caption)>*{border-width:var(--tblr-border-width) 0}.table-bordered>:not(caption)>*>*,.markdown>table>:not(caption)>*>*{border-width:0 var(--tblr-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(2n)>*{--tblr-table-color-type: var(--tblr-table-striped-color);--tblr-table-bg-type: var(--tblr-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--tblr-table-color-type: var(--tblr-table-striped-color);--tblr-table-bg-type: var(--tblr-table-striped-bg)}.table-active{--tblr-table-color-state: var(--tblr-table-active-color);--tblr-table-bg-state: var(--tblr-table-active-bg)}.table-hover>tbody>tr:hover>*{--tblr-table-color-state: var(--tblr-table-hover-color);--tblr-table-bg-state: var(--tblr-table-hover-bg)}.table-primary{--tblr-table-color: #182433;--tblr-table-bg: #cce7e5;--tblr-table-border-color: #a8c0c1;--tblr-table-striped-bg: #c3dddc;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #bad4d3;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #bfd8d8;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-secondary{--tblr-table-color: #182433;--tblr-table-bg: #e2e4e9;--tblr-table-border-color: #babec5;--tblr-table-striped-bg: #d8dae0;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #ced1d7;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #d3d6db;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-success{--tblr-table-color: #182433;--tblr-table-bg: #d5f0da;--tblr-table-border-color: #afc7b9;--tblr-table-striped-bg: #cce6d2;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #c2dcc9;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #c7e1cd;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-info{--tblr-table-color: #182433;--tblr-table-bg: #d9ebf9;--tblr-table-border-color: #b2c3d1;--tblr-table-striped-bg: #cfe1ef;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #c6d7e5;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #cbdcea;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-warning{--tblr-table-color: #182433;--tblr-table-bg: #fde1cd;--tblr-table-border-color: #cfbbae;--tblr-table-striped-bg: #f2d8c5;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e6cebe;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #ecd3c1;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-danger{--tblr-table-color: #182433;--tblr-table-bg: #f7d7d7;--tblr-table-border-color: #cab3b6;--tblr-table-striped-bg: #eccecf;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e1c5c7;--tblr-table-active-color: #f6f8fb;--tblr-table-hover-bg: #e6cacb;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-light{--tblr-table-color: #182433;--tblr-table-bg: #f6f8fb;--tblr-table-border-color: #caced3;--tblr-table-striped-bg: #ebedf1;--tblr-table-striped-color: #182433;--tblr-table-active-bg: #e0e3e7;--tblr-table-active-color: #182433;--tblr-table-hover-bg: #e5e8ec;--tblr-table-hover-color: #182433;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-dark{--tblr-table-color: #f6f8fb;--tblr-table-bg: #182433;--tblr-table-border-color: #444e5b;--tblr-table-striped-bg: #232f3d;--tblr-table-striped-color: #f6f8fb;--tblr-table-active-bg: #2e3947;--tblr-table-active-color: #f6f8fb;--tblr-table-hover-bg: #293442;--tblr-table-hover-color: #f6f8fb;color:var(--tblr-table-color);border-color:var(--tblr-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem;font-size:.875rem;font-weight:var(--tblr-font-weight-medium)}.col-form-label{padding-top:calc(.4375rem + var(--tblr-border-width));padding-bottom:calc(.4375rem + var(--tblr-border-width));margin-bottom:0;font-size:inherit;font-weight:var(--tblr-font-weight-medium);line-height:1.4285714286}.col-form-label-lg{padding-top:calc(.6875rem + var(--tblr-border-width));padding-bottom:calc(.6875rem + var(--tblr-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.0625rem + var(--tblr-border-width));padding-bottom:calc(.0625rem + var(--tblr-border-width));font-size:.75rem}.form-text{margin-top:.25rem;font-size:85.714285%;color:var(--tblr-secondary-color)}.form-control{display:block;width:100%;padding:.4375rem .75rem;font-family:var(--tblr-font-sans-serif);font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-body-color);appearance:none;background-color:var(--tblr-bg-forms);background-clip:padding-box;border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--tblr-body-color);background-color:var(--tblr-bg-forms);border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.4285714286em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:#8a97ab;opacity:1}.form-control:disabled{background-color:var(--tblr-bg-surface-secondary);opacity:1}.form-control::file-selector-button{padding:.4375rem .75rem;margin:-.4375rem -.75rem;margin-inline-end:.75rem;color:var(--tblr-body-color);background-color:var(--tblr-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--tblr-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--tblr-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.4375rem 0;margin-bottom:0;line-height:1.4285714286;color:var(--tblr-body-color);background-color:transparent;border:solid transparent;border-width:var(--tblr-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.4285714286em + .125rem + calc(var(--tblr-border-width) * 2));padding:.0625rem .25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.form-control-sm::file-selector-button{padding:.0625rem .25rem;margin:-.0625rem -.25rem;margin-inline-end:.25rem}.form-control-lg{min-height:calc(1.4285714286em + 1.375rem + calc(var(--tblr-border-width) * 2));padding:.6875rem 1.5rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}.form-control-lg::file-selector-button{padding:.6875rem 1.5rem;margin:-.6875rem -1.5rem;margin-inline-end:1.5rem}textarea.form-control{min-height:calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.4285714286em + .125rem + calc(var(--tblr-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.4285714286em + 1.375rem + calc(var(--tblr-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2));padding:.4375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--tblr-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--tblr-border-radius)}.form-control-color.form-control-sm{height:calc(1.4285714286em + .125rem + calc(var(--tblr-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.4285714286em + 1.375rem + calc(var(--tblr-border-width) * 2))}.form-select{--tblr-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.4375rem 2.25rem .4375rem .75rem;font-family:var(--tblr-font-sans-serif);font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-body-color);appearance:none;background-color:var(--tblr-bg-forms);background-image:var(--tblr-form-select-bg-img),var(--tblr-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--tblr-bg-surface-secondary)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--tblr-body-color)}.form-select-sm{padding-top:.0625rem;padding-bottom:.0625rem;padding-left:.25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.form-select-lg{padding-top:.6875rem;padding-bottom:.6875rem;padding-left:1.5rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}[data-bs-theme=dark] .form-select,body[data-bs-theme=dark] [data-bs-theme=light] .form-select{--tblr-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dce1e7' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.25rem;padding-left:2rem;margin-bottom:.75rem}.form-check .form-check-input{float:left;margin-left:-2rem}.form-check-reverse{padding-right:2rem;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-2rem;margin-left:0}.form-check-input{--tblr-form-check-bg: var(--tblr-bg-forms);flex-shrink:0;width:1.25rem;height:1.25rem;margin-top:.0892857143rem;vertical-align:top;appearance:none;background-color:var(--tblr-form-check-bg);background-image:var(--tblr-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:var(--tblr-border-radius)}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#80c2be;outline:0;box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-check-input:checked{background-color:var(--tblr-primary);border-color:var(--tblr-border-color-translucent)}.form-check-input:checked[type=checkbox]{--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:var(--tblr-primary);border-color:var(--tblr-primary);--tblr-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.7}.form-switch{padding-left:2.5rem}.form-switch .form-check-input{--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23dce1e7'/%3e%3c/svg%3e");width:2rem;margin-left:-2.5rem;background-image:var(--tblr-form-switch-bg);background-position:left center;border-radius:2rem;transition:background-position .15s ease-in-out}.form-switch .form-check-input:focus{--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2380c2be'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5rem;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5rem;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.4}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--tblr-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.25rem;padding:0;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #f6f8fb,0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #f6f8fb,0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.375rem;appearance:none;background-color:var(--tblr-primary);border:2px var(--tblr-border-style) #ffffff;border-radius:1rem;box-shadow:0 .1rem .25rem #0000001a;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b3dad8}.form-range::-webkit-slider-runnable-track{width:100%;height:.25rem;color:transparent;cursor:pointer;background-color:var(--tblr-border-color);border-color:transparent;border-radius:1rem;box-shadow:var(--tblr-box-shadow-inset)}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;background-color:var(--tblr-primary);border:2px var(--tblr-border-style) #ffffff;border-radius:1rem;box-shadow:0 .1rem .25rem #0000001a;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b3dad8}.form-range::-moz-range-track{width:100%;height:.25rem;color:transparent;cursor:pointer;background-color:var(--tblr-border-color);border-color:transparent;border-radius:1rem;box-shadow:var(--tblr-box-shadow-inset)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--tblr-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--tblr-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--tblr-border-width) * 2));min-height:calc(3.5rem + calc(var(--tblr-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--tblr-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--tblr-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:focus~label:after,.form-floating>.form-control:not(:placeholder-shown)~label:after,.form-floating>.form-control-plaintext~label:after,.form-floating>.form-select~label:after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:var(--tblr-bg-forms);border-radius:var(--tblr-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--tblr-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--tblr-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#49566c}.form-floating>:disabled~label:after,.form-floating>.form-control:disabled~label:after{background-color:var(--tblr-bg-surface-secondary)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.4375rem .75rem;font-size:.875rem;font-weight:400;line-height:1.4285714286;color:var(--tblr-gray-500);text-align:center;white-space:nowrap;background-color:var(--tblr-bg-surface-secondary);border:var(--tblr-border-width) solid var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.6875rem 1.5rem;font-size:1.25rem;border-radius:var(--tblr-border-radius-lg)}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.0625rem .25rem;font-size:.75rem;border-radius:var(--tblr-border-radius-sm)}.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):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{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:calc(var(--tblr-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:85.714285%;color:var(--tblr-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:var(--tblr-spacer-2) var(--tblr-spacer-2);margin-top:.1rem;font-size:.765625rem;color:#fff;background-color:var(--tblr-success);border-radius:var(--tblr-border-radius)}.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:var(--tblr-form-valid-border-color);padding-right:calc(1.4285714286em + .875rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.3571428572em + .21875rem) center;background-size:calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--tblr-form-valid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.4285714286em + .875rem);background-position:top calc(.3571428572em + .21875rem) right calc(.3571428572em + .21875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--tblr-form-valid-border-color)}.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"]{--tblr-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--tblr-form-valid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.4285714286em + .875rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--tblr-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--tblr-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--tblr-success-rgb),.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--tblr-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:85.714285%;color:var(--tblr-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:var(--tblr-spacer-2) var(--tblr-spacer-2);margin-top:.1rem;font-size:.765625rem;color:#fff;background-color:var(--tblr-danger);border-radius:var(--tblr-border-radius)}.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:var(--tblr-form-invalid-border-color);padding-right:calc(1.4285714286em + .875rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.3571428572em + .21875rem) center;background-size:calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--tblr-form-invalid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.4285714286em + .875rem);background-position:top calc(.3571428572em + .21875rem) right calc(.3571428572em + .21875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--tblr-form-invalid-border-color)}.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"]{--tblr-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--tblr-form-invalid-border-color);box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.4285714286em + .875rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--tblr-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--tblr-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--tblr-danger-rgb),.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--tblr-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--tblr-btn-padding-x: .5rem;--tblr-btn-padding-y: .25rem;--tblr-btn-font-family: var(--tblr-font-sans-serif);--tblr-btn-font-size: .875rem;--tblr-btn-font-weight: var(--tblr-font-weight-medium);--tblr-btn-line-height: 1.4285714286;--tblr-btn-color: var(--tblr-body-color);--tblr-btn-bg: transparent;--tblr-btn-border-width: var(--tblr-border-width);--tblr-btn-border-color: transparent;--tblr-btn-border-radius: var(--tblr-border-radius);--tblr-btn-hover-border-color: transparent;--tblr-btn-box-shadow: var(--tblr-box-shadow-input);--tblr-btn-disabled-opacity: .4;--tblr-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--tblr-btn-padding-y) var(--tblr-btn-padding-x);font-family:var(--tblr-btn-font-family);font-size:var(--tblr-btn-font-size);font-weight:var(--tblr-btn-font-weight);line-height:var(--tblr-btn-line-height);color:var(--tblr-btn-color);text-align:center;vertical-align:middle;cursor:pointer;user-select:none;border:var(--tblr-btn-border-width) solid var(--tblr-btn-border-color);border-radius:var(--tblr-btn-border-radius);background-color:var(--tblr-btn-bg);box-shadow:var(--tblr-btn-box-shadow);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--tblr-btn-hover-color);text-decoration:none;background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--tblr-btn-color);background-color:var(--tblr-btn-bg);border-color:var(--tblr-btn-border-color)}.btn:focus-visible{color:var(--tblr-btn-hover-color);background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color);outline:0;box-shadow:var(--tblr-btn-box-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--tblr-btn-hover-border-color);outline:0;box-shadow:var(--tblr-btn-box-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--tblr-btn-active-color);background-color:var(--tblr-btn-active-bg);border-color:var(--tblr-btn-active-border-color);box-shadow:var(--tblr-btn-active-shadow)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--tblr-btn-active-shadow),var(--tblr-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--tblr-btn-active-shadow),var(--tblr-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--tblr-btn-disabled-color);pointer-events:none;background-color:var(--tblr-btn-disabled-bg);border-color:var(--tblr-btn-disabled-border-color);opacity:var(--tblr-btn-disabled-opacity);box-shadow:none}.btn-link{--tblr-btn-font-weight: 400;--tblr-btn-color: var(--tblr-link-color);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-link-hover-color);--tblr-btn-hover-border-color: transparent;--tblr-btn-active-color: var(--tblr-link-hover-color);--tblr-btn-active-border-color: transparent;--tblr-btn-disabled-color: #49566c;--tblr-btn-disabled-border-color: transparent;--tblr-btn-box-shadow: 0 0 0 #000;--tblr-btn-focus-shadow-rgb: 37, 150, 144;text-decoration:none}.btn-link:hover,.btn-link:focus-visible{text-decoration:underline}.btn-link:focus-visible{color:var(--tblr-btn-color)}.btn-link:hover{color:var(--tblr-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--tblr-btn-padding-y: .6875rem;--tblr-btn-padding-x: 1.5rem;--tblr-btn-font-size: 1.25rem;--tblr-btn-border-radius: var(--tblr-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--tblr-btn-padding-y: .0625rem;--tblr-btn-padding-x: .25rem;--tblr-btn-font-size: .75rem;--tblr-btn-border-radius: var(--tblr-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-45deg)}.dropdown-menu{--tblr-dropdown-zindex: 1000;--tblr-dropdown-min-width: 11rem;--tblr-dropdown-padding-x: 0;--tblr-dropdown-padding-y: .25rem;--tblr-dropdown-spacer: 1px;--tblr-dropdown-font-size: .875rem;--tblr-dropdown-color: var(--tblr-body-color);--tblr-dropdown-bg: var(--tblr-bg-surface);--tblr-dropdown-border-color: var(--tblr-border-color-translucent);--tblr-dropdown-border-radius: var(--tblr-border-radius);--tblr-dropdown-border-width: var(--tblr-border-width);--tblr-dropdown-inner-border-radius: calc(var(--tblr-border-radius) - var(--tblr-border-width));--tblr-dropdown-divider-bg: var(--tblr-border-color-translucent);--tblr-dropdown-divider-margin-y: var(--tblr-spacer-2);--tblr-dropdown-box-shadow: var(--tblr-box-shadow-dropdown);--tblr-dropdown-link-color: inherit;--tblr-dropdown-link-hover-color: inherit;--tblr-dropdown-link-hover-bg: rgba(var(--tblr-secondary-rgb), .08);--tblr-dropdown-link-active-color: var(--tblr-primary);--tblr-dropdown-link-active-bg: var(--tblr-active-bg);--tblr-dropdown-link-disabled-color: var(--tblr-tertiary-color);--tblr-dropdown-item-padding-x: .75rem;--tblr-dropdown-item-padding-y: .5rem;--tblr-dropdown-header-color: #49566c;--tblr-dropdown-header-padding-x: .75rem;--tblr-dropdown-header-padding-y: .25rem;position:absolute;z-index:var(--tblr-dropdown-zindex);display:none;min-width:var(--tblr-dropdown-min-width);padding:var(--tblr-dropdown-padding-y) var(--tblr-dropdown-padding-x);margin:0;font-size:var(--tblr-dropdown-font-size);color:var(--tblr-dropdown-color);text-align:left;list-style:none;background-color:var(--tblr-dropdown-bg);background-clip:padding-box;border:var(--tblr-dropdown-border-width) solid var(--tblr-dropdown-border-color);border-radius:var(--tblr-dropdown-border-radius);box-shadow:var(--tblr-dropdown-box-shadow)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--tblr-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 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:var(--tblr-dropdown-spacer)}.dropup .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(135deg)}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--tblr-dropdown-spacer)}.dropend .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-135deg)}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--tblr-dropdown-spacer)}.dropstart .dropdown-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(45deg)}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--tblr-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--tblr-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--tblr-dropdown-item-padding-y) var(--tblr-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--tblr-dropdown-link-color);text-align:inherit;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--tblr-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--tblr-dropdown-link-hover-color);text-decoration:none;background-color:var(--tblr-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--tblr-dropdown-link-active-color);text-decoration:none;background-color:var(--tblr-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--tblr-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--tblr-dropdown-header-padding-y) var(--tblr-dropdown-header-padding-x);margin-bottom:0;font-size:.765625rem;color:var(--tblr-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--tblr-dropdown-item-padding-y) var(--tblr-dropdown-item-padding-x);color:var(--tblr-dropdown-link-color)}.dropdown-menu-dark{--tblr-dropdown-color: #b8c4d4;--tblr-dropdown-bg: #182433;--tblr-dropdown-border-color: var(--tblr-border-color-translucent);--tblr-dropdown-box-shadow: ;--tblr-dropdown-link-color: #b8c4d4;--tblr-dropdown-link-hover-color: #ffffff;--tblr-dropdown-divider-bg: var(--tblr-border-color-translucent);--tblr-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--tblr-dropdown-link-active-color: var(--tblr-primary);--tblr-dropdown-link-active-bg: var(--tblr-active-bg);--tblr-dropdown-link-disabled-color: #6c7a91;--tblr-dropdown-header-color: #6c7a91}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--tblr-border-radius)}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--tblr-border-width) * -1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.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:.1875rem;padding-left:.1875rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:1.125rem;padding-left:1.125rem}.btn-group.show .dropdown-toggle{box-shadow:inset 0 3px 5px #00000020}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.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:calc(var(--tblr-border-width) * -1)}.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{--tblr-nav-link-padding-x: .75rem;--tblr-nav-link-padding-y: .5rem;--tblr-nav-link-font-weight: ;--tblr-nav-link-color: var(--tblr-gray-500);--tblr-nav-link-hover-color: var(--tblr-link-hover-color);--tblr-nav-link-disabled-color: var(--tblr-disabled-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--tblr-nav-link-padding-y) var(--tblr-nav-link-padding-x);font-size:var(--tblr-nav-link-font-size);font-weight:var(--tblr-nav-link-font-weight);color:var(--tblr-nav-link-color);background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}.nav-link:hover,.nav-link:focus{color:var(--tblr-nav-link-hover-color);text-decoration:none}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.nav-link.disabled,.nav-link:disabled{color:var(--tblr-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--tblr-nav-tabs-border-width: var(--tblr-border-width);--tblr-nav-tabs-border-color: var(--tblr-border-color);--tblr-nav-tabs-border-radius: var(--tblr-border-radius);--tblr-nav-tabs-link-hover-border-color: var(--tblr-border-color) var(--tblr-border-color) var(--tblr-border-color);--tblr-nav-tabs-link-active-color: var(--tblr-body-color);--tblr-nav-tabs-link-active-bg: var(--tblr-body-bg);--tblr-nav-tabs-link-active-border-color: var(--tblr-border-color) var(--tblr-border-color) var(--tblr-border-color);border-bottom:var(--tblr-nav-tabs-border-width) solid var(--tblr-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--tblr-nav-tabs-border-width));border:var(--tblr-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--tblr-nav-tabs-border-radius);border-top-right-radius:var(--tblr-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--tblr-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--tblr-nav-tabs-link-active-color);background-color:var(--tblr-nav-tabs-link-active-bg);border-color:var(--tblr-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--tblr-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--tblr-nav-pills-border-radius: var(--tblr-border-radius);--tblr-nav-pills-link-active-color: var(--tblr-primary);--tblr-nav-pills-link-active-bg: rgba(var(--tblr-secondary-rgb), .15)}.nav-pills .nav-link{border-radius:var(--tblr-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--tblr-nav-pills-link-active-color);background-color:var(--tblr-nav-pills-link-active-bg)}.nav-underline{--tblr-nav-underline-gap: 1rem;--tblr-nav-underline-border-width: .125rem;--tblr-nav-underline-link-active-color: var(--tblr-emphasis-color);gap:var(--tblr-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--tblr-nav-underline-border-width) solid transparent}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:600;color:var(--tblr-nav-underline-link-active-color);border-bottom-color:currentcolor}.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{--tblr-navbar-padding-x: 0;--tblr-navbar-padding-y: .25rem;--tblr-navbar-color: var(--tblr-muted);--tblr-navbar-hover-color: var(--tblr-body-color) color;--tblr-navbar-disabled-color: var(--tblr-disabled-color);--tblr-navbar-active-color: var(--tblr-body-color) color;--tblr-navbar-brand-padding-y: .5rem;--tblr-navbar-brand-margin-end: 1rem;--tblr-navbar-brand-font-size: 1.25rem;--tblr-navbar-brand-color: var(--tblr-body-color);--tblr-navbar-brand-hover-color: var(--tblr-body-color) color;--tblr-navbar-nav-link-padding-x: .75rem;--tblr-navbar-toggler-padding-y: 0;--tblr-navbar-toggler-padding-x: 0;--tblr-navbar-toggler-font-size: 1rem;--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2824, 36, 51, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--tblr-navbar-toggler-border-color: rgba(var(--tblr-emphasis-color-rgb), .15);--tblr-navbar-toggler-border-radius: var(--tblr-border-radius);--tblr-navbar-toggler-focus-width: 0;--tblr-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--tblr-navbar-padding-y) var(--tblr-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--tblr-navbar-brand-padding-y);padding-bottom:var(--tblr-navbar-brand-padding-y);margin-right:var(--tblr-navbar-brand-margin-end);font-size:var(--tblr-navbar-brand-font-size);color:var(--tblr-navbar-brand-color);white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--tblr-navbar-brand-hover-color);text-decoration:none}.navbar-nav{--tblr-nav-link-padding-x: 0;--tblr-nav-link-padding-y: .5rem;--tblr-nav-link-font-weight: ;--tblr-nav-link-color: var(--tblr-navbar-color);--tblr-nav-link-hover-color: var(--tblr-navbar-hover-color);--tblr-nav-link-disabled-color: var(--tblr-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--tblr-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--tblr-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--tblr-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--tblr-navbar-toggler-padding-y) var(--tblr-navbar-toggler-padding-x);font-size:var(--tblr-navbar-toggler-font-size);line-height:1;color:var(--tblr-navbar-color);background-color:transparent;border:var(--tblr-border-width) solid var(--tblr-navbar-toggler-border-color);border-radius:var(--tblr-navbar-toggler-border-radius);transition:var(--tblr-navbar-toggler-transition)}@media (prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--tblr-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--tblr-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--tblr-scroll-height, 75vh);overflow-y:auto}@media (min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 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:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--tblr-navbar-nav-link-padding-x);padding-left:var(--tblr-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;box-shadow:none;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark],body[data-bs-theme=dark] .navbar[data-bs-theme=light]{--tblr-navbar-color: rgba(255, 255, 255, .7);--tblr-navbar-hover-color: rgba(255, 255, 255, .75);--tblr-navbar-disabled-color: var(--tblr-disabled-color);--tblr-navbar-active-color: #ffffff;--tblr-navbar-brand-color: #ffffff;--tblr-navbar-brand-hover-color: #ffffff;--tblr-navbar-toggler-border-color: rgba(255, 255, 255, .1);--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.7%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon,body[data-bs-theme=dark] [data-bs-theme=light] .navbar-toggler-icon{--tblr-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.7%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--tblr-card-spacer-y: 1rem;--tblr-card-spacer-x: 1.25rem;--tblr-card-title-spacer-y: 1.25rem;--tblr-card-title-color: ;--tblr-card-subtitle-color: ;--tblr-card-border-width: var(--tblr-border-width);--tblr-card-border-color: var(--tblr-border-color-translucent);--tblr-card-border-radius: var(--tblr-border-radius);--tblr-card-box-shadow: var(--tblr-shadow-card);--tblr-card-inner-border-radius: calc(var(--tblr-border-radius) - (var(--tblr-border-width)));--tblr-card-cap-padding-y: 1rem;--tblr-card-cap-padding-x: 1.25rem;--tblr-card-cap-bg: var(--tblr-bg-surface-tertiary);--tblr-card-cap-color: inherit;--tblr-card-height: ;--tblr-card-color: inherit;--tblr-card-bg: var(--tblr-bg-surface);--tblr-card-img-overlay-padding: 1rem;--tblr-card-group-margin: 1.5rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--tblr-card-height);color:var(--tblr-body-color);word-wrap:break-word;background-color:var(--tblr-card-bg);background-clip:border-box;border:var(--tblr-card-border-width) solid var(--tblr-card-border-color);border-radius:var(--tblr-card-border-radius);box-shadow:var(--tblr-card-box-shadow)}.card>hr,.card>.hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--tblr-card-inner-border-radius);border-top-right-radius:var(--tblr-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--tblr-card-inner-border-radius);border-bottom-left-radius:var(--tblr-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--tblr-card-spacer-y) var(--tblr-card-spacer-x);color:var(--tblr-card-color)}.card-title{margin-bottom:var(--tblr-card-title-spacer-y);color:var(--tblr-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--tblr-card-title-spacer-y));margin-bottom:0;color:var(--tblr-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:var(--tblr-card-spacer-x)}.card-header{padding:var(--tblr-card-cap-padding-y) var(--tblr-card-cap-padding-x);margin-bottom:0;color:var(--tblr-card-cap-color);background-color:var(--tblr-card-cap-bg);border-bottom:var(--tblr-card-border-width) solid var(--tblr-card-border-color)}.card-header:first-child{border-radius:var(--tblr-card-inner-border-radius) var(--tblr-card-inner-border-radius) 0 0}.card-footer{padding:var(--tblr-card-cap-padding-y) var(--tblr-card-cap-padding-x);color:var(--tblr-card-cap-color);background-color:var(--tblr-card-cap-bg);border-top:var(--tblr-card-border-width) solid var(--tblr-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--tblr-card-inner-border-radius) var(--tblr-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--tblr-card-cap-padding-x));margin-bottom:calc(-1 * var(--tblr-card-cap-padding-y));margin-left:calc(-.5 * var(--tblr-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--tblr-card-bg);border-bottom-color:var(--tblr-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--tblr-card-cap-padding-x));margin-left:calc(-.5 * var(--tblr-card-cap-padding-x))}.card-img-overlay{position:absolute;inset:0;padding:var(--tblr-card-img-overlay-padding);border-radius:var(--tblr-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--tblr-card-inner-border-radius);border-top-right-radius:var(--tblr-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--tblr-card-inner-border-radius);border-bottom-left-radius:var(--tblr-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--tblr-card-group-margin)}@media (min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--tblr-accordion-color: var(--tblr-body-color);--tblr-accordion-bg: transparent;--tblr-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--tblr-accordion-border-color: var(--tblr-border-color-translucent);--tblr-accordion-border-width: var(--tblr-border-width);--tblr-accordion-border-radius: var(--tblr-border-radius);--tblr-accordion-inner-border-radius: calc(var(--tblr-border-radius) - (var(--tblr-border-width)));--tblr-accordion-btn-padding-x: 1.25rem;--tblr-accordion-btn-padding-y: 1rem;--tblr-accordion-btn-color: var(--tblr-body-color);--tblr-accordion-btn-bg: transparent;--tblr-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23182433' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--tblr-accordion-btn-icon-width: 1rem;--tblr-accordion-btn-icon-transform: rotate(-180deg);--tblr-accordion-btn-icon-transition: transform .2s ease-in-out;--tblr-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23003532' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--tblr-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-accordion-body-padding-x: 1.25rem;--tblr-accordion-body-padding-y: 1rem;--tblr-accordion-active-color: inherit;--tblr-accordion-active-bg: transparent}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--tblr-accordion-btn-padding-y) var(--tblr-accordion-btn-padding-x);font-size:.875rem;color:var(--tblr-accordion-btn-color);text-align:left;background-color:var(--tblr-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--tblr-accordion-transition)}@media (prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--tblr-accordion-active-color);background-color:var(--tblr-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--tblr-accordion-border-width)) 0 var(--tblr-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--tblr-accordion-btn-active-icon);transform:var(--tblr-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--tblr-accordion-btn-icon-width);height:var(--tblr-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--tblr-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--tblr-accordion-btn-icon-width);transition:var(--tblr-accordion-btn-icon-transition)}@media (prefers-reduced-motion: reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--tblr-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--tblr-accordion-color);background-color:var(--tblr-accordion-bg);border:var(--tblr-accordion-border-width) solid var(--tblr-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--tblr-accordion-border-radius);border-top-right-radius:var(--tblr-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--tblr-accordion-inner-border-radius);border-top-right-radius:var(--tblr-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--tblr-accordion-border-radius);border-bottom-left-radius:var(--tblr-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--tblr-accordion-inner-border-radius);border-bottom-left-radius:var(--tblr-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--tblr-accordion-border-radius);border-bottom-left-radius:var(--tblr-accordion-border-radius)}.accordion-body{padding:var(--tblr-accordion-body-padding-y) var(--tblr-accordion-body-padding-x)}.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-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button:after{--tblr-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2366b6b1'%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");--tblr-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2366b6b1'%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")}.breadcrumb{--tblr-breadcrumb-padding-x: 0;--tblr-breadcrumb-padding-y: 0;--tblr-breadcrumb-margin-bottom: 1rem;--tblr-breadcrumb-bg: ;--tblr-breadcrumb-border-radius: ;--tblr-breadcrumb-divider-color: var(--tblr-gray-500);--tblr-breadcrumb-item-padding-x: .5rem;--tblr-breadcrumb-item-active-color: inherit;display:flex;flex-wrap:wrap;padding:var(--tblr-breadcrumb-padding-y) var(--tblr-breadcrumb-padding-x);margin-bottom:var(--tblr-breadcrumb-margin-bottom);font-size:var(--tblr-breadcrumb-font-size);list-style:none;background-color:var(--tblr-breadcrumb-bg);border-radius:var(--tblr-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--tblr-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--tblr-breadcrumb-item-padding-x);color:var(--tblr-breadcrumb-divider-color);content:var(--tblr-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--tblr-breadcrumb-item-active-color)}.pagination{--tblr-pagination-padding-x: .25rem;--tblr-pagination-padding-y: .25rem;--tblr-pagination-font-size: .875rem;--tblr-pagination-color: var(--tblr-gray-500);--tblr-pagination-bg: transparent;--tblr-pagination-border-width: 0;--tblr-pagination-border-color: var(--tblr-border-color);--tblr-pagination-border-radius: var(--tblr-border-radius);--tblr-pagination-hover-color: var(--tblr-link-hover-color);--tblr-pagination-hover-bg: var(--tblr-tertiary-bg);--tblr-pagination-hover-border-color: var(--tblr-border-color);--tblr-pagination-focus-color: var(--tblr-link-hover-color);--tblr-pagination-focus-bg: var(--tblr-secondary-bg);--tblr-pagination-focus-box-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-pagination-active-color: #ffffff;--tblr-pagination-active-bg: var(--tblr-primary);--tblr-pagination-active-border-color: var(--tblr-primary);--tblr-pagination-disabled-color: var(--tblr-disabled-color);--tblr-pagination-disabled-bg: transparent;--tblr-pagination-disabled-border-color: var(--tblr-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--tblr-pagination-padding-y) var(--tblr-pagination-padding-x);font-size:var(--tblr-pagination-font-size);color:var(--tblr-pagination-color);background-color:var(--tblr-pagination-bg);border:var(--tblr-pagination-border-width) solid var(--tblr-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--tblr-pagination-hover-color);text-decoration:none;background-color:var(--tblr-pagination-hover-bg);border-color:var(--tblr-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--tblr-pagination-focus-color);background-color:var(--tblr-pagination-focus-bg);outline:0;box-shadow:var(--tblr-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--tblr-pagination-active-color);background-color:var(--tblr-pagination-active-bg);border-color:var(--tblr-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--tblr-pagination-disabled-color);pointer-events:none;background-color:var(--tblr-pagination-disabled-bg);border-color:var(--tblr-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:-0}.page-item:first-child .page-link{border-top-left-radius:var(--tblr-pagination-border-radius);border-bottom-left-radius:var(--tblr-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--tblr-pagination-border-radius);border-bottom-right-radius:var(--tblr-pagination-border-radius)}.pagination-lg{--tblr-pagination-padding-x: 1.5rem;--tblr-pagination-padding-y: .75rem;--tblr-pagination-font-size: 1.09375rem;--tblr-pagination-border-radius: var(--tblr-border-radius-lg)}.pagination-sm{--tblr-pagination-padding-x: .5rem;--tblr-pagination-padding-y: .25rem;--tblr-pagination-font-size: .765625rem;--tblr-pagination-border-radius: var(--tblr-border-radius-sm)}.badge{--tblr-badge-padding-x: .5em;--tblr-badge-padding-y: .25em;--tblr-badge-font-size: 85.714285%;--tblr-badge-font-weight: var(--tblr-font-weight-medium);--tblr-badge-color: var(--tblr-gray-500);--tblr-badge-border-radius: var(--tblr-border-radius);display:inline-block;padding:var(--tblr-badge-padding-y) var(--tblr-badge-padding-x);font-size:var(--tblr-badge-font-size);font-weight:var(--tblr-badge-font-weight);line-height:1;color:var(--tblr-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--tblr-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--tblr-alert-bg: transparent;--tblr-alert-padding-x: 1rem;--tblr-alert-padding-y: .75rem;--tblr-alert-margin-bottom: 1rem;--tblr-alert-color: inherit;--tblr-alert-border-color: transparent;--tblr-alert-border: var(--tblr-border-width) solid var(--tblr-alert-border-color);--tblr-alert-border-radius: var(--tblr-border-radius);--tblr-alert-link-color: inherit;position:relative;padding:var(--tblr-alert-padding-y) var(--tblr-alert-padding-x);margin-bottom:var(--tblr-alert-margin-bottom);color:var(--tblr-alert-color);background-color:var(--tblr-alert-bg);border:var(--tblr-alert-border);border-radius:var(--tblr-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:var(--tblr-font-weight-bold);color:var(--tblr-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:.9375rem 1rem}.alert-primary{--tblr-alert-color: var(--tblr-primary-text-emphasis);--tblr-alert-bg: var(--tblr-primary-bg-subtle);--tblr-alert-border-color: var(--tblr-primary-border-subtle);--tblr-alert-link-color: var(--tblr-primary-text-emphasis)}.alert-secondary{--tblr-alert-color: var(--tblr-secondary-text-emphasis);--tblr-alert-bg: var(--tblr-secondary-bg-subtle);--tblr-alert-border-color: var(--tblr-secondary-border-subtle);--tblr-alert-link-color: var(--tblr-secondary-text-emphasis)}.alert-success{--tblr-alert-color: var(--tblr-success-text-emphasis);--tblr-alert-bg: var(--tblr-success-bg-subtle);--tblr-alert-border-color: var(--tblr-success-border-subtle);--tblr-alert-link-color: var(--tblr-success-text-emphasis)}.alert-info{--tblr-alert-color: var(--tblr-info-text-emphasis);--tblr-alert-bg: var(--tblr-info-bg-subtle);--tblr-alert-border-color: var(--tblr-info-border-subtle);--tblr-alert-link-color: var(--tblr-info-text-emphasis)}.alert-warning{--tblr-alert-color: var(--tblr-warning-text-emphasis);--tblr-alert-bg: var(--tblr-warning-bg-subtle);--tblr-alert-border-color: var(--tblr-warning-border-subtle);--tblr-alert-link-color: var(--tblr-warning-text-emphasis)}.alert-danger{--tblr-alert-color: var(--tblr-danger-text-emphasis);--tblr-alert-bg: var(--tblr-danger-bg-subtle);--tblr-alert-border-color: var(--tblr-danger-border-subtle);--tblr-alert-link-color: var(--tblr-danger-text-emphasis)}.alert-light{--tblr-alert-color: var(--tblr-light-text-emphasis);--tblr-alert-bg: var(--tblr-light-bg-subtle);--tblr-alert-border-color: var(--tblr-light-border-subtle);--tblr-alert-link-color: var(--tblr-light-text-emphasis)}.alert-dark{--tblr-alert-color: var(--tblr-dark-text-emphasis);--tblr-alert-bg: var(--tblr-dark-bg-subtle);--tblr-alert-border-color: var(--tblr-dark-border-subtle);--tblr-alert-link-color: var(--tblr-dark-text-emphasis)}.alert-muted{--tblr-alert-color: var(--tblr-muted-text-emphasis);--tblr-alert-bg: var(--tblr-muted-bg-subtle);--tblr-alert-border-color: var(--tblr-muted-border-subtle);--tblr-alert-link-color: var(--tblr-muted-text-emphasis)}.alert-blue{--tblr-alert-color: var(--tblr-blue-text-emphasis);--tblr-alert-bg: var(--tblr-blue-bg-subtle);--tblr-alert-border-color: var(--tblr-blue-border-subtle);--tblr-alert-link-color: var(--tblr-blue-text-emphasis)}.alert-azure{--tblr-alert-color: var(--tblr-azure-text-emphasis);--tblr-alert-bg: var(--tblr-azure-bg-subtle);--tblr-alert-border-color: var(--tblr-azure-border-subtle);--tblr-alert-link-color: var(--tblr-azure-text-emphasis)}.alert-indigo{--tblr-alert-color: var(--tblr-indigo-text-emphasis);--tblr-alert-bg: var(--tblr-indigo-bg-subtle);--tblr-alert-border-color: var(--tblr-indigo-border-subtle);--tblr-alert-link-color: var(--tblr-indigo-text-emphasis)}.alert-purple{--tblr-alert-color: var(--tblr-purple-text-emphasis);--tblr-alert-bg: var(--tblr-purple-bg-subtle);--tblr-alert-border-color: var(--tblr-purple-border-subtle);--tblr-alert-link-color: var(--tblr-purple-text-emphasis)}.alert-pink{--tblr-alert-color: var(--tblr-pink-text-emphasis);--tblr-alert-bg: var(--tblr-pink-bg-subtle);--tblr-alert-border-color: var(--tblr-pink-border-subtle);--tblr-alert-link-color: var(--tblr-pink-text-emphasis)}.alert-red{--tblr-alert-color: var(--tblr-red-text-emphasis);--tblr-alert-bg: var(--tblr-red-bg-subtle);--tblr-alert-border-color: var(--tblr-red-border-subtle);--tblr-alert-link-color: var(--tblr-red-text-emphasis)}.alert-orange{--tblr-alert-color: var(--tblr-orange-text-emphasis);--tblr-alert-bg: var(--tblr-orange-bg-subtle);--tblr-alert-border-color: var(--tblr-orange-border-subtle);--tblr-alert-link-color: var(--tblr-orange-text-emphasis)}.alert-yellow{--tblr-alert-color: var(--tblr-yellow-text-emphasis);--tblr-alert-bg: var(--tblr-yellow-bg-subtle);--tblr-alert-border-color: var(--tblr-yellow-border-subtle);--tblr-alert-link-color: var(--tblr-yellow-text-emphasis)}.alert-lime{--tblr-alert-color: var(--tblr-lime-text-emphasis);--tblr-alert-bg: var(--tblr-lime-bg-subtle);--tblr-alert-border-color: var(--tblr-lime-border-subtle);--tblr-alert-link-color: var(--tblr-lime-text-emphasis)}.alert-green{--tblr-alert-color: var(--tblr-green-text-emphasis);--tblr-alert-bg: var(--tblr-green-bg-subtle);--tblr-alert-border-color: var(--tblr-green-border-subtle);--tblr-alert-link-color: var(--tblr-green-text-emphasis)}.alert-teal{--tblr-alert-color: var(--tblr-teal-text-emphasis);--tblr-alert-bg: var(--tblr-teal-bg-subtle);--tblr-alert-border-color: var(--tblr-teal-border-subtle);--tblr-alert-link-color: var(--tblr-teal-text-emphasis)}.alert-cyan{--tblr-alert-color: var(--tblr-cyan-text-emphasis);--tblr-alert-bg: var(--tblr-cyan-bg-subtle);--tblr-alert-border-color: var(--tblr-cyan-border-subtle);--tblr-alert-link-color: var(--tblr-cyan-text-emphasis)}.alert-x{--tblr-alert-color: var(--tblr-x-text-emphasis);--tblr-alert-bg: var(--tblr-x-bg-subtle);--tblr-alert-border-color: var(--tblr-x-border-subtle);--tblr-alert-link-color: var(--tblr-x-text-emphasis)}.alert-facebook{--tblr-alert-color: var(--tblr-facebook-text-emphasis);--tblr-alert-bg: var(--tblr-facebook-bg-subtle);--tblr-alert-border-color: var(--tblr-facebook-border-subtle);--tblr-alert-link-color: var(--tblr-facebook-text-emphasis)}.alert-twitter{--tblr-alert-color: var(--tblr-twitter-text-emphasis);--tblr-alert-bg: var(--tblr-twitter-bg-subtle);--tblr-alert-border-color: var(--tblr-twitter-border-subtle);--tblr-alert-link-color: var(--tblr-twitter-text-emphasis)}.alert-linkedin{--tblr-alert-color: var(--tblr-linkedin-text-emphasis);--tblr-alert-bg: var(--tblr-linkedin-bg-subtle);--tblr-alert-border-color: var(--tblr-linkedin-border-subtle);--tblr-alert-link-color: var(--tblr-linkedin-text-emphasis)}.alert-google{--tblr-alert-color: var(--tblr-google-text-emphasis);--tblr-alert-bg: var(--tblr-google-bg-subtle);--tblr-alert-border-color: var(--tblr-google-border-subtle);--tblr-alert-link-color: var(--tblr-google-text-emphasis)}.alert-youtube{--tblr-alert-color: var(--tblr-youtube-text-emphasis);--tblr-alert-bg: var(--tblr-youtube-bg-subtle);--tblr-alert-border-color: var(--tblr-youtube-border-subtle);--tblr-alert-link-color: var(--tblr-youtube-text-emphasis)}.alert-vimeo{--tblr-alert-color: var(--tblr-vimeo-text-emphasis);--tblr-alert-bg: var(--tblr-vimeo-bg-subtle);--tblr-alert-border-color: var(--tblr-vimeo-border-subtle);--tblr-alert-link-color: var(--tblr-vimeo-text-emphasis)}.alert-dribbble{--tblr-alert-color: var(--tblr-dribbble-text-emphasis);--tblr-alert-bg: var(--tblr-dribbble-bg-subtle);--tblr-alert-border-color: var(--tblr-dribbble-border-subtle);--tblr-alert-link-color: var(--tblr-dribbble-text-emphasis)}.alert-github{--tblr-alert-color: var(--tblr-github-text-emphasis);--tblr-alert-bg: var(--tblr-github-bg-subtle);--tblr-alert-border-color: var(--tblr-github-border-subtle);--tblr-alert-link-color: var(--tblr-github-text-emphasis)}.alert-instagram{--tblr-alert-color: var(--tblr-instagram-text-emphasis);--tblr-alert-bg: var(--tblr-instagram-bg-subtle);--tblr-alert-border-color: var(--tblr-instagram-border-subtle);--tblr-alert-link-color: var(--tblr-instagram-text-emphasis)}.alert-pinterest{--tblr-alert-color: var(--tblr-pinterest-text-emphasis);--tblr-alert-bg: var(--tblr-pinterest-bg-subtle);--tblr-alert-border-color: var(--tblr-pinterest-border-subtle);--tblr-alert-link-color: var(--tblr-pinterest-text-emphasis)}.alert-vk{--tblr-alert-color: var(--tblr-vk-text-emphasis);--tblr-alert-bg: var(--tblr-vk-bg-subtle);--tblr-alert-border-color: var(--tblr-vk-border-subtle);--tblr-alert-link-color: var(--tblr-vk-text-emphasis)}.alert-rss{--tblr-alert-color: var(--tblr-rss-text-emphasis);--tblr-alert-bg: var(--tblr-rss-bg-subtle);--tblr-alert-border-color: var(--tblr-rss-border-subtle);--tblr-alert-link-color: var(--tblr-rss-text-emphasis)}.alert-flickr{--tblr-alert-color: var(--tblr-flickr-text-emphasis);--tblr-alert-bg: var(--tblr-flickr-bg-subtle);--tblr-alert-border-color: var(--tblr-flickr-border-subtle);--tblr-alert-link-color: var(--tblr-flickr-text-emphasis)}.alert-bitbucket{--tblr-alert-color: var(--tblr-bitbucket-text-emphasis);--tblr-alert-bg: var(--tblr-bitbucket-bg-subtle);--tblr-alert-border-color: var(--tblr-bitbucket-border-subtle);--tblr-alert-link-color: var(--tblr-bitbucket-text-emphasis)}.alert-tabler{--tblr-alert-color: var(--tblr-tabler-text-emphasis);--tblr-alert-bg: var(--tblr-tabler-bg-subtle);--tblr-alert-border-color: var(--tblr-tabler-border-subtle);--tblr-alert-link-color: var(--tblr-tabler-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress,.progress-stacked{--tblr-progress-height: .5rem;--tblr-progress-font-size: .65625rem;--tblr-progress-bg: var(--tblr-border-color);--tblr-progress-border-radius: var(--tblr-border-radius);--tblr-progress-box-shadow: var(--tblr-box-shadow-inset);--tblr-progress-bar-color: #ffffff;--tblr-progress-bar-bg: var(--tblr-primary);--tblr-progress-bar-transition: width .6s ease;display:flex;height:var(--tblr-progress-height);overflow:hidden;font-size:var(--tblr-progress-font-size);background-color:var(--tblr-progress-bg);border-radius:var(--tblr-progress-border-radius);box-shadow:var(--tblr-progress-box-shadow)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--tblr-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--tblr-progress-bar-bg);transition:var(--tblr-progress-bar-transition)}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--tblr-progress-height) var(--tblr-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--tblr-list-group-color: var(--tblr-body-color);--tblr-list-group-bg: inherit;--tblr-list-group-border-color: var(--tblr-border-color);--tblr-list-group-border-width: var(--tblr-border-width);--tblr-list-group-border-radius: var(--tblr-border-radius);--tblr-list-group-item-padding-x: 1.25rem;--tblr-list-group-item-padding-y: 1rem;--tblr-list-group-action-color: inherit;--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: rgba(var(--tblr-secondary-rgb), .08);--tblr-list-group-action-active-color: var(--tblr-body-color);--tblr-list-group-action-active-bg: var(--tblr-secondary-bg);--tblr-list-group-disabled-color: var(--tblr-secondary-color);--tblr-list-group-disabled-bg: inherit;--tblr-list-group-active-color: inherit;--tblr-list-group-active-bg: var(--tblr-active-bg);--tblr-list-group-active-border-color: var(--tblr-border-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--tblr-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--tblr-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--tblr-list-group-action-hover-color);text-decoration:none;background-color:var(--tblr-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--tblr-list-group-action-active-color);background-color:var(--tblr-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--tblr-list-group-item-padding-y) var(--tblr-list-group-item-padding-x);color:var(--tblr-list-group-color);background-color:var(--tblr-list-group-bg);border:var(--tblr-list-group-border-width) solid var(--tblr-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--tblr-list-group-disabled-color);pointer-events:none;background-color:var(--tblr-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--tblr-list-group-active-color);background-color:var(--tblr-list-group-active-bg);border-color:var(--tblr-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--tblr-list-group-border-width));border-top-width:var(--tblr-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}@media (min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}@media (min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--tblr-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--tblr-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--tblr-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--tblr-list-group-border-width));border-left-width:var(--tblr-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--tblr-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--tblr-list-group-color: var(--tblr-primary-text-emphasis);--tblr-list-group-bg: var(--tblr-primary-bg-subtle);--tblr-list-group-border-color: var(--tblr-primary-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-primary-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-primary-border-subtle);--tblr-list-group-active-color: var(--tblr-primary-bg-subtle);--tblr-list-group-active-bg: var(--tblr-primary-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-primary-text-emphasis)}.list-group-item-secondary{--tblr-list-group-color: var(--tblr-secondary-text-emphasis);--tblr-list-group-bg: var(--tblr-secondary-bg-subtle);--tblr-list-group-border-color: var(--tblr-secondary-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-secondary-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-secondary-border-subtle);--tblr-list-group-active-color: var(--tblr-secondary-bg-subtle);--tblr-list-group-active-bg: var(--tblr-secondary-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-secondary-text-emphasis)}.list-group-item-success{--tblr-list-group-color: var(--tblr-success-text-emphasis);--tblr-list-group-bg: var(--tblr-success-bg-subtle);--tblr-list-group-border-color: var(--tblr-success-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-success-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-success-border-subtle);--tblr-list-group-active-color: var(--tblr-success-bg-subtle);--tblr-list-group-active-bg: var(--tblr-success-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-success-text-emphasis)}.list-group-item-info{--tblr-list-group-color: var(--tblr-info-text-emphasis);--tblr-list-group-bg: var(--tblr-info-bg-subtle);--tblr-list-group-border-color: var(--tblr-info-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-info-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-info-border-subtle);--tblr-list-group-active-color: var(--tblr-info-bg-subtle);--tblr-list-group-active-bg: var(--tblr-info-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-info-text-emphasis)}.list-group-item-warning{--tblr-list-group-color: var(--tblr-warning-text-emphasis);--tblr-list-group-bg: var(--tblr-warning-bg-subtle);--tblr-list-group-border-color: var(--tblr-warning-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-warning-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-warning-border-subtle);--tblr-list-group-active-color: var(--tblr-warning-bg-subtle);--tblr-list-group-active-bg: var(--tblr-warning-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-warning-text-emphasis)}.list-group-item-danger{--tblr-list-group-color: var(--tblr-danger-text-emphasis);--tblr-list-group-bg: var(--tblr-danger-bg-subtle);--tblr-list-group-border-color: var(--tblr-danger-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-danger-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-danger-border-subtle);--tblr-list-group-active-color: var(--tblr-danger-bg-subtle);--tblr-list-group-active-bg: var(--tblr-danger-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-danger-text-emphasis)}.list-group-item-light{--tblr-list-group-color: var(--tblr-light-text-emphasis);--tblr-list-group-bg: var(--tblr-light-bg-subtle);--tblr-list-group-border-color: var(--tblr-light-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-light-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-light-border-subtle);--tblr-list-group-active-color: var(--tblr-light-bg-subtle);--tblr-list-group-active-bg: var(--tblr-light-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-light-text-emphasis)}.list-group-item-dark{--tblr-list-group-color: var(--tblr-dark-text-emphasis);--tblr-list-group-bg: var(--tblr-dark-bg-subtle);--tblr-list-group-border-color: var(--tblr-dark-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-dark-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-dark-border-subtle);--tblr-list-group-active-color: var(--tblr-dark-bg-subtle);--tblr-list-group-active-bg: var(--tblr-dark-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-dark-text-emphasis)}.list-group-item-muted{--tblr-list-group-color: var(--tblr-muted-text-emphasis);--tblr-list-group-bg: var(--tblr-muted-bg-subtle);--tblr-list-group-border-color: var(--tblr-muted-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-muted-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-muted-border-subtle);--tblr-list-group-active-color: var(--tblr-muted-bg-subtle);--tblr-list-group-active-bg: var(--tblr-muted-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-muted-text-emphasis)}.list-group-item-blue{--tblr-list-group-color: var(--tblr-blue-text-emphasis);--tblr-list-group-bg: var(--tblr-blue-bg-subtle);--tblr-list-group-border-color: var(--tblr-blue-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-blue-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-blue-border-subtle);--tblr-list-group-active-color: var(--tblr-blue-bg-subtle);--tblr-list-group-active-bg: var(--tblr-blue-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-blue-text-emphasis)}.list-group-item-azure{--tblr-list-group-color: var(--tblr-azure-text-emphasis);--tblr-list-group-bg: var(--tblr-azure-bg-subtle);--tblr-list-group-border-color: var(--tblr-azure-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-azure-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-azure-border-subtle);--tblr-list-group-active-color: var(--tblr-azure-bg-subtle);--tblr-list-group-active-bg: var(--tblr-azure-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-azure-text-emphasis)}.list-group-item-indigo{--tblr-list-group-color: var(--tblr-indigo-text-emphasis);--tblr-list-group-bg: var(--tblr-indigo-bg-subtle);--tblr-list-group-border-color: var(--tblr-indigo-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-indigo-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-indigo-border-subtle);--tblr-list-group-active-color: var(--tblr-indigo-bg-subtle);--tblr-list-group-active-bg: var(--tblr-indigo-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-indigo-text-emphasis)}.list-group-item-purple{--tblr-list-group-color: var(--tblr-purple-text-emphasis);--tblr-list-group-bg: var(--tblr-purple-bg-subtle);--tblr-list-group-border-color: var(--tblr-purple-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-purple-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-purple-border-subtle);--tblr-list-group-active-color: var(--tblr-purple-bg-subtle);--tblr-list-group-active-bg: var(--tblr-purple-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-purple-text-emphasis)}.list-group-item-pink{--tblr-list-group-color: var(--tblr-pink-text-emphasis);--tblr-list-group-bg: var(--tblr-pink-bg-subtle);--tblr-list-group-border-color: var(--tblr-pink-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-pink-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-pink-border-subtle);--tblr-list-group-active-color: var(--tblr-pink-bg-subtle);--tblr-list-group-active-bg: var(--tblr-pink-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-pink-text-emphasis)}.list-group-item-red{--tblr-list-group-color: var(--tblr-red-text-emphasis);--tblr-list-group-bg: var(--tblr-red-bg-subtle);--tblr-list-group-border-color: var(--tblr-red-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-red-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-red-border-subtle);--tblr-list-group-active-color: var(--tblr-red-bg-subtle);--tblr-list-group-active-bg: var(--tblr-red-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-red-text-emphasis)}.list-group-item-orange{--tblr-list-group-color: var(--tblr-orange-text-emphasis);--tblr-list-group-bg: var(--tblr-orange-bg-subtle);--tblr-list-group-border-color: var(--tblr-orange-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-orange-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-orange-border-subtle);--tblr-list-group-active-color: var(--tblr-orange-bg-subtle);--tblr-list-group-active-bg: var(--tblr-orange-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-orange-text-emphasis)}.list-group-item-yellow{--tblr-list-group-color: var(--tblr-yellow-text-emphasis);--tblr-list-group-bg: var(--tblr-yellow-bg-subtle);--tblr-list-group-border-color: var(--tblr-yellow-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-yellow-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-yellow-border-subtle);--tblr-list-group-active-color: var(--tblr-yellow-bg-subtle);--tblr-list-group-active-bg: var(--tblr-yellow-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-yellow-text-emphasis)}.list-group-item-lime{--tblr-list-group-color: var(--tblr-lime-text-emphasis);--tblr-list-group-bg: var(--tblr-lime-bg-subtle);--tblr-list-group-border-color: var(--tblr-lime-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-lime-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-lime-border-subtle);--tblr-list-group-active-color: var(--tblr-lime-bg-subtle);--tblr-list-group-active-bg: var(--tblr-lime-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-lime-text-emphasis)}.list-group-item-green{--tblr-list-group-color: var(--tblr-green-text-emphasis);--tblr-list-group-bg: var(--tblr-green-bg-subtle);--tblr-list-group-border-color: var(--tblr-green-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-green-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-green-border-subtle);--tblr-list-group-active-color: var(--tblr-green-bg-subtle);--tblr-list-group-active-bg: var(--tblr-green-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-green-text-emphasis)}.list-group-item-teal{--tblr-list-group-color: var(--tblr-teal-text-emphasis);--tblr-list-group-bg: var(--tblr-teal-bg-subtle);--tblr-list-group-border-color: var(--tblr-teal-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-teal-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-teal-border-subtle);--tblr-list-group-active-color: var(--tblr-teal-bg-subtle);--tblr-list-group-active-bg: var(--tblr-teal-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-teal-text-emphasis)}.list-group-item-cyan{--tblr-list-group-color: var(--tblr-cyan-text-emphasis);--tblr-list-group-bg: var(--tblr-cyan-bg-subtle);--tblr-list-group-border-color: var(--tblr-cyan-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-cyan-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-cyan-border-subtle);--tblr-list-group-active-color: var(--tblr-cyan-bg-subtle);--tblr-list-group-active-bg: var(--tblr-cyan-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-cyan-text-emphasis)}.list-group-item-x{--tblr-list-group-color: var(--tblr-x-text-emphasis);--tblr-list-group-bg: var(--tblr-x-bg-subtle);--tblr-list-group-border-color: var(--tblr-x-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-x-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-x-border-subtle);--tblr-list-group-active-color: var(--tblr-x-bg-subtle);--tblr-list-group-active-bg: var(--tblr-x-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-x-text-emphasis)}.list-group-item-facebook{--tblr-list-group-color: var(--tblr-facebook-text-emphasis);--tblr-list-group-bg: var(--tblr-facebook-bg-subtle);--tblr-list-group-border-color: var(--tblr-facebook-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-facebook-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-facebook-border-subtle);--tblr-list-group-active-color: var(--tblr-facebook-bg-subtle);--tblr-list-group-active-bg: var(--tblr-facebook-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-facebook-text-emphasis)}.list-group-item-twitter{--tblr-list-group-color: var(--tblr-twitter-text-emphasis);--tblr-list-group-bg: var(--tblr-twitter-bg-subtle);--tblr-list-group-border-color: var(--tblr-twitter-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-twitter-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-twitter-border-subtle);--tblr-list-group-active-color: var(--tblr-twitter-bg-subtle);--tblr-list-group-active-bg: var(--tblr-twitter-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-twitter-text-emphasis)}.list-group-item-linkedin{--tblr-list-group-color: var(--tblr-linkedin-text-emphasis);--tblr-list-group-bg: var(--tblr-linkedin-bg-subtle);--tblr-list-group-border-color: var(--tblr-linkedin-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-linkedin-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-linkedin-border-subtle);--tblr-list-group-active-color: var(--tblr-linkedin-bg-subtle);--tblr-list-group-active-bg: var(--tblr-linkedin-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-linkedin-text-emphasis)}.list-group-item-google{--tblr-list-group-color: var(--tblr-google-text-emphasis);--tblr-list-group-bg: var(--tblr-google-bg-subtle);--tblr-list-group-border-color: var(--tblr-google-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-google-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-google-border-subtle);--tblr-list-group-active-color: var(--tblr-google-bg-subtle);--tblr-list-group-active-bg: var(--tblr-google-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-google-text-emphasis)}.list-group-item-youtube{--tblr-list-group-color: var(--tblr-youtube-text-emphasis);--tblr-list-group-bg: var(--tblr-youtube-bg-subtle);--tblr-list-group-border-color: var(--tblr-youtube-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-youtube-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-youtube-border-subtle);--tblr-list-group-active-color: var(--tblr-youtube-bg-subtle);--tblr-list-group-active-bg: var(--tblr-youtube-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-youtube-text-emphasis)}.list-group-item-vimeo{--tblr-list-group-color: var(--tblr-vimeo-text-emphasis);--tblr-list-group-bg: var(--tblr-vimeo-bg-subtle);--tblr-list-group-border-color: var(--tblr-vimeo-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-vimeo-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-vimeo-border-subtle);--tblr-list-group-active-color: var(--tblr-vimeo-bg-subtle);--tblr-list-group-active-bg: var(--tblr-vimeo-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-vimeo-text-emphasis)}.list-group-item-dribbble{--tblr-list-group-color: var(--tblr-dribbble-text-emphasis);--tblr-list-group-bg: var(--tblr-dribbble-bg-subtle);--tblr-list-group-border-color: var(--tblr-dribbble-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-dribbble-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-dribbble-border-subtle);--tblr-list-group-active-color: var(--tblr-dribbble-bg-subtle);--tblr-list-group-active-bg: var(--tblr-dribbble-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-dribbble-text-emphasis)}.list-group-item-github{--tblr-list-group-color: var(--tblr-github-text-emphasis);--tblr-list-group-bg: var(--tblr-github-bg-subtle);--tblr-list-group-border-color: var(--tblr-github-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-github-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-github-border-subtle);--tblr-list-group-active-color: var(--tblr-github-bg-subtle);--tblr-list-group-active-bg: var(--tblr-github-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-github-text-emphasis)}.list-group-item-instagram{--tblr-list-group-color: var(--tblr-instagram-text-emphasis);--tblr-list-group-bg: var(--tblr-instagram-bg-subtle);--tblr-list-group-border-color: var(--tblr-instagram-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-instagram-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-instagram-border-subtle);--tblr-list-group-active-color: var(--tblr-instagram-bg-subtle);--tblr-list-group-active-bg: var(--tblr-instagram-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-instagram-text-emphasis)}.list-group-item-pinterest{--tblr-list-group-color: var(--tblr-pinterest-text-emphasis);--tblr-list-group-bg: var(--tblr-pinterest-bg-subtle);--tblr-list-group-border-color: var(--tblr-pinterest-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-pinterest-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-pinterest-border-subtle);--tblr-list-group-active-color: var(--tblr-pinterest-bg-subtle);--tblr-list-group-active-bg: var(--tblr-pinterest-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-pinterest-text-emphasis)}.list-group-item-vk{--tblr-list-group-color: var(--tblr-vk-text-emphasis);--tblr-list-group-bg: var(--tblr-vk-bg-subtle);--tblr-list-group-border-color: var(--tblr-vk-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-vk-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-vk-border-subtle);--tblr-list-group-active-color: var(--tblr-vk-bg-subtle);--tblr-list-group-active-bg: var(--tblr-vk-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-vk-text-emphasis)}.list-group-item-rss{--tblr-list-group-color: var(--tblr-rss-text-emphasis);--tblr-list-group-bg: var(--tblr-rss-bg-subtle);--tblr-list-group-border-color: var(--tblr-rss-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-rss-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-rss-border-subtle);--tblr-list-group-active-color: var(--tblr-rss-bg-subtle);--tblr-list-group-active-bg: var(--tblr-rss-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-rss-text-emphasis)}.list-group-item-flickr{--tblr-list-group-color: var(--tblr-flickr-text-emphasis);--tblr-list-group-bg: var(--tblr-flickr-bg-subtle);--tblr-list-group-border-color: var(--tblr-flickr-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-flickr-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-flickr-border-subtle);--tblr-list-group-active-color: var(--tblr-flickr-bg-subtle);--tblr-list-group-active-bg: var(--tblr-flickr-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-flickr-text-emphasis)}.list-group-item-bitbucket{--tblr-list-group-color: var(--tblr-bitbucket-text-emphasis);--tblr-list-group-bg: var(--tblr-bitbucket-bg-subtle);--tblr-list-group-border-color: var(--tblr-bitbucket-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-bitbucket-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-bitbucket-border-subtle);--tblr-list-group-active-color: var(--tblr-bitbucket-bg-subtle);--tblr-list-group-active-bg: var(--tblr-bitbucket-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-bitbucket-text-emphasis)}.list-group-item-tabler{--tblr-list-group-color: var(--tblr-tabler-text-emphasis);--tblr-list-group-bg: var(--tblr-tabler-bg-subtle);--tblr-list-group-border-color: var(--tblr-tabler-border-subtle);--tblr-list-group-action-hover-color: var(--tblr-emphasis-color);--tblr-list-group-action-hover-bg: var(--tblr-tabler-border-subtle);--tblr-list-group-action-active-color: var(--tblr-emphasis-color);--tblr-list-group-action-active-bg: var(--tblr-tabler-border-subtle);--tblr-list-group-active-color: var(--tblr-tabler-bg-subtle);--tblr-list-group-active-bg: var(--tblr-tabler-text-emphasis);--tblr-list-group-active-border-color: var(--tblr-tabler-text-emphasis)}.btn-close{--tblr-btn-close-color: #182433;--tblr-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23182433'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--tblr-btn-close-opacity: .4;--tblr-btn-close-hover-opacity: .75;--tblr-btn-close-focus-shadow: 0 0 0 .25rem rgba(var(--tblr-primary-rgb), .25);--tblr-btn-close-focus-opacity: 1;--tblr-btn-close-disabled-opacity: .25;--tblr-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em;color:var(--tblr-btn-close-color);background:transparent var(--tblr-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:4px;opacity:var(--tblr-btn-close-opacity)}.btn-close:hover{color:var(--tblr-btn-close-color);text-decoration:none;opacity:var(--tblr-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--tblr-btn-close-focus-shadow);opacity:var(--tblr-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;opacity:var(--tblr-btn-close-disabled-opacity)}.btn-close-white,[data-bs-theme=dark] .btn-close,body[data-bs-theme=dark] [data-bs-theme=light] .btn-close{filter:var(--tblr-btn-close-white-filter)}.toast{--tblr-toast-zindex: 1090;--tblr-toast-padding-x: .75rem;--tblr-toast-padding-y: .5rem;--tblr-toast-spacing: calc(var(--tblr-page-padding) * 2);--tblr-toast-max-width: 350px;--tblr-toast-font-size: .875rem;--tblr-toast-color: ;--tblr-toast-bg: var(--tblr-bg-surface);--tblr-toast-border-width: var(--tblr-border-width);--tblr-toast-border-color: var(--tblr-border-color);--tblr-toast-border-radius: var(--tblr-border-radius);--tblr-toast-box-shadow: var(--tblr-box-shadow);--tblr-toast-header-color: var(--tblr-gray-500);--tblr-toast-header-bg: rgba(var(--tblr-body-bg-rgb), .85);--tblr-toast-header-border-color: var(--tblr-border-color);width:var(--tblr-toast-max-width);max-width:100%;font-size:var(--tblr-toast-font-size);color:var(--tblr-toast-color);pointer-events:auto;background-color:var(--tblr-toast-bg);background-clip:padding-box;border:var(--tblr-toast-border-width) solid var(--tblr-toast-border-color);box-shadow:var(--tblr-toast-box-shadow);border-radius:var(--tblr-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--tblr-toast-zindex: 1090;position:absolute;z-index:var(--tblr-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--tblr-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--tblr-toast-padding-y) var(--tblr-toast-padding-x);color:var(--tblr-toast-header-color);background-color:var(--tblr-toast-header-bg);background-clip:padding-box;border-bottom:var(--tblr-toast-border-width) solid var(--tblr-toast-header-border-color);border-top-left-radius:calc(var(--tblr-toast-border-radius) - var(--tblr-toast-border-width));border-top-right-radius:calc(var(--tblr-toast-border-radius) - var(--tblr-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--tblr-toast-padding-x));margin-left:var(--tblr-toast-padding-x)}.toast-body{padding:var(--tblr-toast-padding-x);word-wrap:break-word}.modal{--tblr-modal-zindex: 1055;--tblr-modal-width: 540px;--tblr-modal-padding: 1.5rem;--tblr-modal-margin: .5rem;--tblr-modal-color: ;--tblr-modal-bg: var(--tblr-bg-surface);--tblr-modal-border-color: transparent;--tblr-modal-border-width: var(--tblr-border-width);--tblr-modal-border-radius: var(--tblr-border-radius-lg);--tblr-modal-box-shadow: var(--tblr-box-shadow-sm);--tblr-modal-inner-border-radius: calc(var(--tblr-modal-border-radius) - 1px);--tblr-modal-header-padding-x: 1.5rem;--tblr-modal-header-padding-y: 1.5rem;--tblr-modal-header-padding: 1.5rem;--tblr-modal-header-border-color: var(--tblr-border-color);--tblr-modal-header-border-width: var(--tblr-border-width);--tblr-modal-title-line-height: 1.4285714286;--tblr-modal-footer-gap: .75rem;--tblr-modal-footer-bg: var(--tblr-bg-surface-tertiary);--tblr-modal-footer-border-color: var(--tblr-border-color);--tblr-modal-footer-border-width: var(--tblr-border-width);position:fixed;top:0;left:0;z-index:var(--tblr-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--tblr-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translateY(-1rem)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--tblr-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--tblr-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--tblr-modal-color);pointer-events:auto;background-color:var(--tblr-modal-bg);background-clip:padding-box;border:var(--tblr-modal-border-width) solid var(--tblr-modal-border-color);border-radius:var(--tblr-modal-border-radius);box-shadow:var(--tblr-modal-box-shadow);outline:0}.modal-backdrop{--tblr-backdrop-zindex: 1050;--tblr-backdrop-bg: #182433;--tblr-backdrop-opacity: .24;position:fixed;top:0;left:0;z-index:var(--tblr-backdrop-zindex);width:100vw;height:100vh;background-color:var(--tblr-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--tblr-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--tblr-modal-header-padding);border-bottom:var(--tblr-modal-header-border-width) solid var(--tblr-modal-header-border-color);border-top-left-radius:var(--tblr-modal-inner-border-radius);border-top-right-radius:var(--tblr-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--tblr-modal-header-padding-y) * .5) calc(var(--tblr-modal-header-padding-x) * .5);margin:calc(-.5 * var(--tblr-modal-header-padding-y)) calc(-.5 * var(--tblr-modal-header-padding-x)) calc(-.5 * var(--tblr-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--tblr-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--tblr-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--tblr-modal-padding) - var(--tblr-modal-footer-gap) * .5);background-color:var(--tblr-modal-footer-bg);border-top:var(--tblr-modal-footer-border-width) solid var(--tblr-modal-footer-border-color);border-bottom-right-radius:var(--tblr-modal-inner-border-radius);border-bottom-left-radius:var(--tblr-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--tblr-modal-footer-gap) * .5)}@media (min-width: 576px){.modal{--tblr-modal-margin: 1.75rem;--tblr-modal-box-shadow: var(--tblr-box-shadow)}.modal-dialog{max-width:var(--tblr-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--tblr-modal-width: 380px}}@media (min-width: 992px){.modal-lg,.modal-xl{--tblr-modal-width: 720px}}@media (min-width: 1200px){.modal-xl{--tblr-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width: 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,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--tblr-tooltip-zindex: 1080;--tblr-tooltip-max-width: 200px;--tblr-tooltip-padding-x: var(--tblr-spacer-2);--tblr-tooltip-padding-y: var(--tblr-spacer-2);--tblr-tooltip-margin: ;--tblr-tooltip-font-size: .765625rem;--tblr-tooltip-color: var(--tblr-light);--tblr-tooltip-bg: var(--tblr-bg-surface-dark);--tblr-tooltip-border-radius: var(--tblr-border-radius);--tblr-tooltip-opacity: .9;--tblr-tooltip-arrow-width: .8rem;--tblr-tooltip-arrow-height: .4rem;z-index:var(--tblr-tooltip-zindex);display:block;margin:var(--tblr-tooltip-margin);font-family:var(--tblr-font-sans-serif);font-style:normal;font-weight:400;line-height:1.4285714286;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--tblr-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--tblr-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--tblr-tooltip-arrow-width);height:var(--tblr-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1 * var(--tblr-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before{top:-1px;border-width:var(--tblr-tooltip-arrow-height) calc(var(--tblr-tooltip-arrow-width) * .5) 0;border-top-color:var(--tblr-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1 * var(--tblr-tooltip-arrow-height));width:var(--tblr-tooltip-arrow-height);height:var(--tblr-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before{right:-1px;border-width:calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height) calc(var(--tblr-tooltip-arrow-width) * .5) 0;border-right-color:var(--tblr-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1 * var(--tblr-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height);border-bottom-color:var(--tblr-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1 * var(--tblr-tooltip-arrow-height));width:var(--tblr-tooltip-arrow-height);height:var(--tblr-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before{left:-1px;border-width:calc(var(--tblr-tooltip-arrow-width) * .5) 0 calc(var(--tblr-tooltip-arrow-width) * .5) var(--tblr-tooltip-arrow-height);border-left-color:var(--tblr-tooltip-bg)}.tooltip-inner{max-width:var(--tblr-tooltip-max-width);padding:var(--tblr-tooltip-padding-y) var(--tblr-tooltip-padding-x);color:var(--tblr-tooltip-color);text-align:center;background-color:var(--tblr-tooltip-bg);border-radius:var(--tblr-tooltip-border-radius)}.popover{--tblr-popover-zindex: 1070;--tblr-popover-max-width: 276px;--tblr-popover-font-size: .765625rem;--tblr-popover-bg: var(--tblr-bg-surface);--tblr-popover-border-width: var(--tblr-border-width);--tblr-popover-border-color: var(--tblr-border-color);--tblr-popover-border-radius: var(--tblr-border-radius-lg);--tblr-popover-inner-border-radius: calc(var(--tblr-border-radius-lg) - var(--tblr-border-width));--tblr-popover-box-shadow: var(--tblr-box-shadow);--tblr-popover-header-padding-x: 1rem;--tblr-popover-header-padding-y: .5rem;--tblr-popover-header-font-size: .875rem;--tblr-popover-header-color: inherit;--tblr-popover-header-bg: transparent;--tblr-popover-body-padding-x: 1rem;--tblr-popover-body-padding-y: 1rem;--tblr-popover-body-color: inherit;--tblr-popover-arrow-width: 1rem;--tblr-popover-arrow-height: .5rem;--tblr-popover-arrow-border: var(--tblr-popover-border-color);z-index:var(--tblr-popover-zindex);display:block;max-width:var(--tblr-popover-max-width);font-family:var(--tblr-font-sans-serif);font-style:normal;font-weight:400;line-height:1.4285714286;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--tblr-popover-font-size);word-wrap:break-word;background-color:var(--tblr-popover-bg);background-clip:padding-box;border:var(--tblr-popover-border-width) solid var(--tblr-popover-border-color);border-radius:var(--tblr-popover-border-radius);box-shadow:var(--tblr-popover-box-shadow)}.popover .popover-arrow{display:block;width:var(--tblr-popover-arrow-width);height:var(--tblr-popover-arrow-height)}.popover .popover-arrow:before,.popover .popover-arrow:after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width))}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{border-width:var(--tblr-popover-arrow-height) calc(var(--tblr-popover-arrow-width) * .5) 0}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before{bottom:0;border-top-color:var(--tblr-popover-arrow-border)}.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{bottom:var(--tblr-popover-border-width);border-top-color:var(--tblr-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width));width:var(--tblr-popover-arrow-height);height:var(--tblr-popover-arrow-width)}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{border-width:calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height) calc(var(--tblr-popover-arrow-width) * .5) 0}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before{left:0;border-right-color:var(--tblr-popover-arrow-border)}.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{left:var(--tblr-popover-border-width);border-right-color:var(--tblr-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width))}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{border-width:0 calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height)}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before{top:0;border-bottom-color:var(--tblr-popover-arrow-border)}.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{top:var(--tblr-popover-border-width);border-bottom-color:var(--tblr-popover-bg)}.bs-popover-bottom .popover-header:before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--tblr-popover-arrow-width);margin-left:calc(-.5 * var(--tblr-popover-arrow-width));content:"";border-bottom:var(--tblr-popover-border-width) solid var(--tblr-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1 * (var(--tblr-popover-arrow-height)) - var(--tblr-popover-border-width));width:var(--tblr-popover-arrow-height);height:var(--tblr-popover-arrow-width)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{border-width:calc(var(--tblr-popover-arrow-width) * .5) 0 calc(var(--tblr-popover-arrow-width) * .5) var(--tblr-popover-arrow-height)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before{right:0;border-left-color:var(--tblr-popover-arrow-border)}.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{right:var(--tblr-popover-border-width);border-left-color:var(--tblr-popover-bg)}.popover-header{padding:var(--tblr-popover-header-padding-y) var(--tblr-popover-header-padding-x);margin-bottom:0;font-size:var(--tblr-popover-header-font-size);color:var(--tblr-popover-header-color);background-color:var(--tblr-popover-header-bg);border-bottom:var(--tblr-popover-border-width) solid var(--tblr-popover-border-color);border-top-left-radius:var(--tblr-popover-inner-border-radius);border-top-right-radius:var(--tblr-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--tblr-popover-body-padding-y) var(--tblr-popover-body-padding-x);color:var(--tblr-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .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:translate(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translate(-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 .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:.5;transition:opacity .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:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:1.5rem;height:1.5rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='15 18 9 12 15 6'%3e%3c/polyline%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='9 18 15 12 9 6'%3e%3c/polyline%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%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-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}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--tblr-spinner-width);height:var(--tblr-spinner-height);vertical-align:var(--tblr-spinner-vertical-align);border-radius:50%;animation:var(--tblr-spinner-animation-speed) linear infinite var(--tblr-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--tblr-spinner-width: 1.5rem;--tblr-spinner-height: 1.5rem;--tblr-spinner-vertical-align: -.125em;--tblr-spinner-border-width: 2px;--tblr-spinner-animation-speed: .75s;--tblr-spinner-animation-name: spinner-border;border:var(--tblr-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--tblr-spinner-width: 1rem;--tblr-spinner-height: 1rem;--tblr-spinner-border-width: 1px}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--tblr-spinner-width: 1.5rem;--tblr-spinner-height: 1.5rem;--tblr-spinner-vertical-align: -.125em;--tblr-spinner-animation-speed: .75s;--tblr-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--tblr-spinner-width: 1rem;--tblr-spinner-height: 1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--tblr-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--tblr-offcanvas-zindex: 1045;--tblr-offcanvas-width: 400px;--tblr-offcanvas-height: 30vh;--tblr-offcanvas-padding-x: 1.5rem;--tblr-offcanvas-padding-y: 1.5rem;--tblr-offcanvas-color: var(--tblr-body-color);--tblr-offcanvas-bg: var(--tblr-bg-surface);--tblr-offcanvas-border-width: var(--tblr-border-width);--tblr-offcanvas-border-color: var(--tblr-border-color);--tblr-offcanvas-box-shadow: var(--tblr-box-shadow-sm);--tblr-offcanvas-transition: transform .3s ease-in-out;--tblr-offcanvas-title-line-height: 1.4285714286}@media (max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 575.98px) and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media (min-width: 576px){.offcanvas-sm{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 767.98px) and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media (min-width: 768px){.offcanvas-md{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 991.98px) and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media (min-width: 992px){.offcanvas-lg{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media (min-width: 1200px){.offcanvas-xl{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}}@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media (min-width: 1400px){.offcanvas-xxl{--tblr-offcanvas-height: auto;--tblr-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--tblr-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--tblr-offcanvas-color);visibility:hidden;background-color:var(--tblr-offcanvas-bg);background-clip:padding-box;outline:0;box-shadow:var(--tblr-offcanvas-box-shadow);transition:var(--tblr-offcanvas-transition)}@media (prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--tblr-offcanvas-width);border-right:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--tblr-offcanvas-width);border-left:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-bottom:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--tblr-offcanvas-height);max-height:100%;border-top:var(--tblr-offcanvas-border-width) solid var(--tblr-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#182433}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.24}.offcanvas-header{display:flex;align-items:center;padding:var(--tblr-offcanvas-padding-y) var(--tblr-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--tblr-offcanvas-padding-y) * .5) calc(var(--tblr-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--tblr-offcanvas-padding-y)) calc(-.5 * var(--tblr-offcanvas-padding-x)) calc(-.5 * var(--tblr-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--tblr-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--tblr-offcanvas-padding-y) var(--tblr-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.2}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.1}}.placeholder-wave{mask-image:linear-gradient(130deg,#000 55%,#000000e6,#000 95%);mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#f6f8fb!important;background-color:RGBA(var(--tblr-primary-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-secondary,.text-bg-gray{color:#f6f8fb!important;background-color:RGBA(var(--tblr-secondary-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-success{color:#f6f8fb!important;background-color:RGBA(var(--tblr-success-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-info{color:#f6f8fb!important;background-color:RGBA(var(--tblr-info-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-warning{color:#f6f8fb!important;background-color:RGBA(var(--tblr-warning-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-danger{color:#f6f8fb!important;background-color:RGBA(var(--tblr-danger-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-light,.text-bg-white{color:#182433!important;background-color:RGBA(var(--tblr-light-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-dark,.text-bg-black{color:#f6f8fb!important;background-color:RGBA(var(--tblr-dark-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-muted{color:#f6f8fb!important;background-color:RGBA(var(--tblr-muted-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-blue{color:#f6f8fb!important;background-color:RGBA(var(--tblr-blue-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-azure{color:#f6f8fb!important;background-color:RGBA(var(--tblr-azure-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-indigo{color:#f6f8fb!important;background-color:RGBA(var(--tblr-indigo-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-purple{color:#f6f8fb!important;background-color:RGBA(var(--tblr-purple-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-pink{color:#f6f8fb!important;background-color:RGBA(var(--tblr-pink-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-red{color:#f6f8fb!important;background-color:RGBA(var(--tblr-red-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-orange{color:#f6f8fb!important;background-color:RGBA(var(--tblr-orange-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-yellow{color:#f6f8fb!important;background-color:RGBA(var(--tblr-yellow-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-lime{color:#f6f8fb!important;background-color:RGBA(var(--tblr-lime-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-green{color:#f6f8fb!important;background-color:RGBA(var(--tblr-green-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-teal{color:#f6f8fb!important;background-color:RGBA(var(--tblr-teal-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-cyan{color:#f6f8fb!important;background-color:RGBA(var(--tblr-cyan-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-x{color:#f6f8fb!important;background-color:RGBA(var(--tblr-x-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-facebook{color:#f6f8fb!important;background-color:RGBA(var(--tblr-facebook-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-twitter{color:#f6f8fb!important;background-color:RGBA(var(--tblr-twitter-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-linkedin{color:#f6f8fb!important;background-color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-google{color:#f6f8fb!important;background-color:RGBA(var(--tblr-google-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-youtube{color:#f6f8fb!important;background-color:RGBA(var(--tblr-youtube-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-vimeo{color:#f6f8fb!important;background-color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-dribbble{color:#f6f8fb!important;background-color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-github{color:#f6f8fb!important;background-color:RGBA(var(--tblr-github-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-instagram{color:#f6f8fb!important;background-color:RGBA(var(--tblr-instagram-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-pinterest{color:#f6f8fb!important;background-color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-vk{color:#f6f8fb!important;background-color:RGBA(var(--tblr-vk-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-rss{color:#f6f8fb!important;background-color:RGBA(var(--tblr-rss-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-flickr{color:#f6f8fb!important;background-color:RGBA(var(--tblr-flickr-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-bitbucket{color:#f6f8fb!important;background-color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-bg-opacity, 1))!important}.text-bg-tabler{color:#f6f8fb!important;background-color:RGBA(var(--tblr-tabler-rgb),var(--tblr-bg-opacity, 1))!important}.link-primary{color:RGBA(var(--tblr-primary-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-primary-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-primary:hover,.link-primary:focus{color:RGBA(0,106,100,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,106,100,var(--tblr-link-underline-opacity, 1))!important}.link-secondary{color:RGBA(var(--tblr-secondary-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-secondary-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86,98,116,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(86,98,116,var(--tblr-link-underline-opacity, 1))!important}.link-success{color:RGBA(var(--tblr-success-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-success-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-success:hover,.link-success:focus{color:RGBA(38,143,54,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(38,143,54,var(--tblr-link-underline-opacity, 1))!important}.link-info{color:RGBA(var(--tblr-info-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-info-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-info:hover,.link-info:focus{color:RGBA(53,122,180,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,122,180,var(--tblr-link-underline-opacity, 1))!important}.link-warning{color:RGBA(var(--tblr-warning-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-warning-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-warning:hover,.link-warning:focus{color:RGBA(198,82,6,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(198,82,6,var(--tblr-link-underline-opacity, 1))!important}.link-danger{color:RGBA(var(--tblr-danger-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-danger-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-danger:hover,.link-danger:focus{color:RGBA(171,46,46,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,46,46,var(--tblr-link-underline-opacity, 1))!important}.link-light{color:RGBA(var(--tblr-light-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-light-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-light:hover,.link-light:focus{color:RGBA(248,249,252,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(248,249,252,var(--tblr-link-underline-opacity, 1))!important}.link-dark{color:RGBA(var(--tblr-dark-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-dark-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-dark:hover,.link-dark:focus{color:RGBA(19,29,41,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,29,41,var(--tblr-link-underline-opacity, 1))!important}.link-muted{color:RGBA(var(--tblr-muted-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-muted-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-muted:hover,.link-muted:focus{color:RGBA(86,98,116,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(86,98,116,var(--tblr-link-underline-opacity, 1))!important}.link-blue{color:RGBA(var(--tblr-blue-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-blue-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-blue:hover,.link-blue:focus{color:RGBA(5,89,167,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(5,89,167,var(--tblr-link-underline-opacity, 1))!important}.link-azure{color:RGBA(var(--tblr-azure-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-azure-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-azure:hover,.link-azure:focus{color:RGBA(53,122,180,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,122,180,var(--tblr-link-underline-opacity, 1))!important}.link-indigo{color:RGBA(var(--tblr-indigo-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-indigo-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-indigo:hover,.link-indigo:focus{color:RGBA(53,79,188,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(53,79,188,var(--tblr-link-underline-opacity, 1))!important}.link-purple{color:RGBA(var(--tblr-purple-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-purple-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-purple:hover,.link-purple:focus{color:RGBA(139,50,161,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(139,50,161,var(--tblr-link-underline-opacity, 1))!important}.link-pink{color:RGBA(var(--tblr-pink-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-pink-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-pink:hover,.link-pink:focus{color:RGBA(171,41,86,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,41,86,var(--tblr-link-underline-opacity, 1))!important}.link-red{color:RGBA(var(--tblr-red-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-red-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-red:hover,.link-red:focus{color:RGBA(171,46,46,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(171,46,46,var(--tblr-link-underline-opacity, 1))!important}.link-orange{color:RGBA(var(--tblr-orange-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-orange-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-orange:hover,.link-orange:focus{color:RGBA(198,82,6,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(198,82,6,var(--tblr-link-underline-opacity, 1))!important}.link-yellow{color:RGBA(var(--tblr-yellow-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-yellow-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-yellow:hover,.link-yellow:focus{color:RGBA(196,127,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(196,127,0,var(--tblr-link-underline-opacity, 1))!important}.link-lime{color:RGBA(var(--tblr-lime-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-lime-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-lime:hover,.link-lime:focus{color:RGBA(93,147,18,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(93,147,18,var(--tblr-link-underline-opacity, 1))!important}.link-green{color:RGBA(var(--tblr-green-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-green-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-green:hover,.link-green:focus{color:RGBA(38,143,54,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(38,143,54,var(--tblr-link-underline-opacity, 1))!important}.link-teal{color:RGBA(var(--tblr-teal-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-teal-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-teal:hover,.link-teal:focus{color:RGBA(10,133,96,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(10,133,96,var(--tblr-link-underline-opacity, 1))!important}.link-cyan{color:RGBA(var(--tblr-cyan-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-cyan-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-cyan:hover,.link-cyan:focus{color:RGBA(18,130,147,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(18,130,147,var(--tblr-link-underline-opacity, 1))!important}.link-x{color:RGBA(var(--tblr-x-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-x-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-x:hover,.link-x:focus{color:RGBA(0,0,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,0,0,var(--tblr-link-underline-opacity, 1))!important}.link-facebook{color:RGBA(var(--tblr-facebook-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-facebook-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-facebook:hover,.link-facebook:focus{color:RGBA(19,95,194,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,95,194,var(--tblr-link-underline-opacity, 1))!important}.link-twitter{color:RGBA(var(--tblr-twitter-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-twitter-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-twitter:hover,.link-twitter:focus{color:RGBA(23,129,194,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(23,129,194,var(--tblr-link-underline-opacity, 1))!important}.link-linkedin{color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-linkedin-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-linkedin:hover,.link-linkedin:focus{color:RGBA(8,82,155,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(8,82,155,var(--tblr-link-underline-opacity, 1))!important}.link-google{color:RGBA(var(--tblr-google-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-google-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-google:hover,.link-google:focus{color:RGBA(176,62,52,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(176,62,52,var(--tblr-link-underline-opacity, 1))!important}.link-youtube{color:RGBA(var(--tblr-youtube-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-youtube-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-youtube:hover,.link-youtube:focus{color:RGBA(204,0,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(204,0,0,var(--tblr-link-underline-opacity, 1))!important}.link-vimeo{color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-vimeo-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-vimeo:hover,.link-vimeo:focus{color:RGBA(21,146,187,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(21,146,187,var(--tblr-link-underline-opacity, 1))!important}.link-dribbble{color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-dribbble-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-dribbble:hover,.link-dribbble:focus{color:RGBA(187,61,110,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(187,61,110,var(--tblr-link-underline-opacity, 1))!important}.link-github{color:RGBA(var(--tblr-github-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-github-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-github:hover,.link-github:focus{color:RGBA(19,18,18,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(19,18,18,var(--tblr-link-underline-opacity, 1))!important}.link-instagram{color:RGBA(var(--tblr-instagram-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-instagram-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-instagram:hover,.link-instagram:focus{color:RGBA(182,51,76,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(182,51,76,var(--tblr-link-underline-opacity, 1))!important}.link-pinterest{color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-pinterest-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-pinterest:hover,.link-pinterest:focus{color:RGBA(151,6,22,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(151,6,22,var(--tblr-link-underline-opacity, 1))!important}.link-vk{color:RGBA(var(--tblr-vk-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-vk-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-vk:hover,.link-vk:focus{color:RGBA(79,105,134,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(79,105,134,var(--tblr-link-underline-opacity, 1))!important}.link-rss{color:RGBA(var(--tblr-rss-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-rss-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-rss:hover,.link-rss:focus{color:RGBA(204,132,0,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(204,132,0,var(--tblr-link-underline-opacity, 1))!important}.link-flickr{color:RGBA(var(--tblr-flickr-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-flickr-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-flickr:hover,.link-flickr:focus{color:RGBA(0,79,176,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,79,176,var(--tblr-link-underline-opacity, 1))!important}.link-bitbucket{color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-bitbucket-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-bitbucket:hover,.link-bitbucket:focus{color:RGBA(0,66,163,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(0,66,163,var(--tblr-link-underline-opacity, 1))!important}.link-tabler{color:RGBA(var(--tblr-tabler-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-tabler-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-tabler:hover,.link-tabler:focus{color:RGBA(5,89,167,var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(5,89,167,var(--tblr-link-underline-opacity, 1))!important}.link-body-emphasis{color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-opacity, 1))!important;text-decoration-color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-opacity, .75))!important;text-decoration-color:RGBA(var(--tblr-emphasis-color-rgb),var(--tblr-link-underline-opacity, .75))!important}.focus-ring:focus{outline:0;box-shadow:var(--tblr-focus-ring-x, 0) var(--tblr-focus-ring-y, 0) var(--tblr-focus-ring-blur, 0) var(--tblr-focus-ring-width) var(--tblr-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-opacity, .5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--tblr-icon-link-transform, translate3d(.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--tblr-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--tblr-aspect-ratio: 100%}.ratio-2x1{--tblr-aspect-ratio: 50%}.ratio-1x2{--tblr-aspect-ratio: 200%}.ratio-3x1{--tblr-aspect-ratio: 33.3333333333%}.ratio-1x3{--tblr-aspect-ratio: 300%}.ratio-4x1{--tblr-aspect-ratio: 25%}.ratio-1x4{--tblr-aspect-ratio: 400%}.ratio-4x3{--tblr-aspect-ratio: 75%}.ratio-3x4{--tblr-aspect-ratio: 133.3333333333%}.ratio-16x9{--tblr-aspect-ratio: 56.25%}.ratio-9x16{--tblr-aspect-ratio: 177.7777777778%}.ratio-21x9{--tblr-aspect-ratio: 42.8571428571%}.ratio-9x21{--tblr-aspect-ratio: 233.3333333333%}.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:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media (min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){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}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute!important}.stretched-link:after{position:absolute;inset:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--tblr-border-width);min-height:1em;background-color:currentcolor;opacity:.16}.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}.object-fit-contain{object-fit:contain!important}.object-fit-cover{object-fit:cover!important}.object-fit-fill{object-fit:fill!important}.object-fit-scale{object-fit:scale-down!important}.object-fit-none{object-fit:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y: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-inline-grid{display:inline-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:var(--tblr-box-shadow)!important}.shadow-sm{box-shadow:var(--tblr-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--tblr-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--tblr-focus-ring-color: rgba(var(--tblr-primary-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-secondary{--tblr-focus-ring-color: rgba(var(--tblr-secondary-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-success{--tblr-focus-ring-color: rgba(var(--tblr-success-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-info{--tblr-focus-ring-color: rgba(var(--tblr-info-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-warning{--tblr-focus-ring-color: rgba(var(--tblr-warning-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-danger{--tblr-focus-ring-color: rgba(var(--tblr-danger-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-light{--tblr-focus-ring-color: rgba(var(--tblr-light-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-dark{--tblr-focus-ring-color: rgba(var(--tblr-dark-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-muted{--tblr-focus-ring-color: rgba(var(--tblr-muted-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-blue{--tblr-focus-ring-color: rgba(var(--tblr-blue-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-azure{--tblr-focus-ring-color: rgba(var(--tblr-azure-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-indigo{--tblr-focus-ring-color: rgba(var(--tblr-indigo-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-purple{--tblr-focus-ring-color: rgba(var(--tblr-purple-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-pink{--tblr-focus-ring-color: rgba(var(--tblr-pink-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-red{--tblr-focus-ring-color: rgba(var(--tblr-red-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-orange{--tblr-focus-ring-color: rgba(var(--tblr-orange-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-yellow{--tblr-focus-ring-color: rgba(var(--tblr-yellow-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-lime{--tblr-focus-ring-color: rgba(var(--tblr-lime-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-green{--tblr-focus-ring-color: rgba(var(--tblr-green-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-teal{--tblr-focus-ring-color: rgba(var(--tblr-teal-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-cyan{--tblr-focus-ring-color: rgba(var(--tblr-cyan-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-x{--tblr-focus-ring-color: rgba(var(--tblr-x-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-facebook{--tblr-focus-ring-color: rgba(var(--tblr-facebook-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-twitter{--tblr-focus-ring-color: rgba(var(--tblr-twitter-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-linkedin{--tblr-focus-ring-color: rgba(var(--tblr-linkedin-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-google{--tblr-focus-ring-color: rgba(var(--tblr-google-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-youtube{--tblr-focus-ring-color: rgba(var(--tblr-youtube-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-vimeo{--tblr-focus-ring-color: rgba(var(--tblr-vimeo-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-dribbble{--tblr-focus-ring-color: rgba(var(--tblr-dribbble-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-github{--tblr-focus-ring-color: rgba(var(--tblr-github-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-instagram{--tblr-focus-ring-color: rgba(var(--tblr-instagram-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-pinterest{--tblr-focus-ring-color: rgba(var(--tblr-pinterest-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-vk{--tblr-focus-ring-color: rgba(var(--tblr-vk-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-rss{--tblr-focus-ring-color: rgba(var(--tblr-rss-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-flickr{--tblr-focus-ring-color: rgba(var(--tblr-flickr-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-bitbucket{--tblr-focus-ring-color: rgba(var(--tblr-bitbucket-rgb), var(--tblr-focus-ring-opacity))}.focus-ring-tabler{--tblr-focus-ring-color: rgba(var(--tblr-tabler-rgb), var(--tblr-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-wide{border:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-0{border:0!important}.border-top{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-top-wide{border-top:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-end-wide{border-right:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-bottom-wide{border-bottom:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-start-wide{border-left:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-start-0{border-left:0!important}.border-primary-subtle{border-color:var(--tblr-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--tblr-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--tblr-success-border-subtle)!important}.border-info-subtle{border-color:var(--tblr-info-border-subtle)!important}.border-warning-subtle{border-color:var(--tblr-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--tblr-danger-border-subtle)!important}.border-light-subtle{border-color:var(--tblr-light-border-subtle)!important}.border-dark-subtle{border-color:var(--tblr-dark-border-subtle)!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}.border-opacity-10{--tblr-border-opacity: .1}.border-opacity-25{--tblr-border-opacity: .25}.border-opacity-50{--tblr-border-opacity: .5}.border-opacity-75{--tblr-border-opacity: .75}.border-opacity-100{--tblr-border-opacity: 1}.w-25{width:25%!important}.w-33{width:33.33333%!important}.w-50{width:50%!important}.w-66{width:66.66666%!important}.w-75{width:75%!important}.w-100{width:100%!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-33{height:33.33333%!important}.h-50{height:50%!important}.h-66{height:66.66666%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:2rem!important}.m-6{margin:2.5rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:2rem!important;margin-left:2rem!important}.mx-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:2rem!important}.mt-6{margin-top:2.5rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:2rem!important}.me-6{margin-right:2.5rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:2rem!important}.mb-6{margin-bottom:2.5rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:2rem!important}.ms-6{margin-left:2.5rem!important}.ms-auto{margin-left:auto!important}.m-n1{margin:-.25rem!important}.m-n2{margin:-.5rem!important}.m-n3{margin:-1rem!important}.m-n4{margin:-1.5rem!important}.m-n5{margin:-2rem!important}.m-n6{margin:-2.5rem!important}.mx-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-n1{margin-top:-.25rem!important}.mt-n2{margin-top:-.5rem!important}.mt-n3{margin-top:-1rem!important}.mt-n4{margin-top:-1.5rem!important}.mt-n5{margin-top:-2rem!important}.mt-n6{margin-top:-2.5rem!important}.me-n1{margin-right:-.25rem!important}.me-n2{margin-right:-.5rem!important}.me-n3{margin-right:-1rem!important}.me-n4{margin-right:-1.5rem!important}.me-n5{margin-right:-2rem!important}.me-n6{margin-right:-2.5rem!important}.mb-n1{margin-bottom:-.25rem!important}.mb-n2{margin-bottom:-.5rem!important}.mb-n3{margin-bottom:-1rem!important}.mb-n4{margin-bottom:-1.5rem!important}.mb-n5{margin-bottom:-2rem!important}.mb-n6{margin-bottom:-2.5rem!important}.ms-n1{margin-left:-.25rem!important}.ms-n2{margin-left:-.5rem!important}.ms-n3{margin-left:-1rem!important}.ms-n4{margin-left:-1.5rem!important}.ms-n5{margin-left:-2rem!important}.ms-n6{margin-left:-2.5rem!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:2rem!important}.p-6{padding:2.5rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:2rem!important;padding-left:2rem!important}.px-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:2rem!important}.pt-6{padding-top:2.5rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:2rem!important}.pe-6{padding-right:2.5rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:2rem!important}.pb-6{padding-bottom:2.5rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:2rem!important}.ps-6{padding-left:2.5rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:2rem!important}.gap-6{gap:2.5rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:2rem!important}.row-gap-6{row-gap:2.5rem!important}.column-gap-0{column-gap:0!important}.column-gap-1{column-gap:.25rem!important}.column-gap-2{column-gap:.5rem!important}.column-gap-3{column-gap:1rem!important}.column-gap-4{column-gap:1.5rem!important}.column-gap-5{column-gap:2rem!important}.column-gap-6{column-gap:2.5rem!important}.font-monospace{font-family:var(--tblr-font-monospace)!important}.fs-1{font-size:1.5rem!important}.fs-2{font-size:1.25rem!important}.fs-3{font-size:1rem!important}.fs-4{font-size:.875rem!important}.fs-5{font-size:.75rem!important}.fs-6{font-size:.625rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold,.fw-bold{font-weight:600!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.1428571429!important}.lh-base{line-height:1.4285714286!important}.lh-lg{line-height:1.7142857143!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-muted{--tblr-text-opacity: 1;color:var(--tblr-secondary-color)!important}.text-black{--tblr-text-opacity: 1;color:rgba(var(--tblr-black-rgb),var(--tblr-text-opacity))!important}.text-white{--tblr-text-opacity: 1;color:rgba(var(--tblr-white-rgb),var(--tblr-text-opacity))!important}.text-body{--tblr-text-opacity: 1;color:rgba(var(--tblr-body-color-rgb),var(--tblr-text-opacity))!important}.text-black-50{--tblr-text-opacity: 1;color:#00000080!important}.text-white-50{--tblr-text-opacity: 1;color:#ffffff80!important}.text-body-secondary{--tblr-text-opacity: 1;color:var(--tblr-secondary-color)!important}.text-body-tertiary{--tblr-text-opacity: 1;color:var(--tblr-tertiary-color)!important}.text-body-emphasis{--tblr-text-opacity: 1;color:var(--tblr-emphasis-color)!important}.text-reset{--tblr-text-opacity: 1;color:inherit!important}.text-opacity-25{--tblr-text-opacity: .25}.text-opacity-50{--tblr-text-opacity: .5}.text-opacity-75{--tblr-text-opacity: .75}.text-opacity-100{--tblr-text-opacity: 1}.text-primary-emphasis{color:var(--tblr-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--tblr-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--tblr-success-text-emphasis)!important}.text-info-emphasis{color:var(--tblr-info-text-emphasis)!important}.text-warning-emphasis{color:var(--tblr-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--tblr-danger-text-emphasis)!important}.text-light-emphasis{color:var(--tblr-light-text-emphasis)!important}.text-dark-emphasis{color:var(--tblr-dark-text-emphasis)!important}.link-opacity-10,.link-opacity-10-hover:hover{--tblr-link-opacity: .1}.link-opacity-25,.link-opacity-25-hover:hover{--tblr-link-opacity: .25}.link-opacity-50,.link-opacity-50-hover:hover{--tblr-link-opacity: .5}.link-opacity-75,.link-opacity-75-hover:hover{--tblr-link-opacity: .75}.link-opacity-100,.link-opacity-100-hover:hover{--tblr-link-opacity: 1}.link-offset-1,.link-offset-1-hover:hover{text-underline-offset:.125em!important}.link-offset-2,.link-offset-2-hover:hover{text-underline-offset:.25em!important}.link-offset-3,.link-offset-3-hover:hover{text-underline-offset:.375em!important}.link-underline-primary{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-primary-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-secondary{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-secondary-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-success{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-success-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-info{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-info-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-warning{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-warning-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-danger{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-danger-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-light{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-light-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-dark{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-dark-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-muted{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-muted-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-blue{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-blue-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-azure{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-azure-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-indigo{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-indigo-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-purple{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-purple-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-pink{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-pink-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-red{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-red-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-orange{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-orange-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-yellow{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-yellow-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-lime{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-lime-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-green{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-green-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-teal{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-teal-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-cyan{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-cyan-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-x{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-x-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-facebook{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-facebook-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-twitter{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-twitter-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-linkedin{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-google{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-google-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-youtube{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-youtube-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-vimeo{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-dribbble{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-github{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-github-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-instagram{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-instagram-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-pinterest{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-vk{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-vk-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-rss{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-rss-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-flickr{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-flickr-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-bitbucket{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-link-underline-opacity))!important}.link-underline-tabler{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-tabler-rgb),var(--tblr-link-underline-opacity))!important}.link-underline{--tblr-link-underline-opacity: 1;text-decoration-color:rgba(var(--tblr-link-color-rgb),var(--tblr-link-underline-opacity, 1))!important}.link-underline-opacity-0,.link-underline-opacity-0-hover:hover{--tblr-link-underline-opacity: 0}.link-underline-opacity-10,.link-underline-opacity-10-hover:hover{--tblr-link-underline-opacity: .1}.link-underline-opacity-25,.link-underline-opacity-25-hover:hover{--tblr-link-underline-opacity: .25}.link-underline-opacity-50,.link-underline-opacity-50-hover:hover{--tblr-link-underline-opacity: .5}.link-underline-opacity-75,.link-underline-opacity-75-hover:hover{--tblr-link-underline-opacity: .75}.link-underline-opacity-100,.link-underline-opacity-100-hover:hover{--tblr-link-underline-opacity: 1}.bg-black{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-black-rgb),var(--tblr-bg-opacity))!important}.bg-body{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-body-bg-rgb),var(--tblr-bg-opacity))!important}.bg-transparent{--tblr-bg-opacity: 1;background-color:transparent!important}.bg-body-secondary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-secondary-bg-rgb),var(--tblr-bg-opacity))!important}.bg-body-tertiary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-tertiary-bg-rgb),var(--tblr-bg-opacity))!important}.bg-opacity-10{--tblr-bg-opacity: .1}.bg-opacity-25{--tblr-bg-opacity: .25}.bg-opacity-50{--tblr-bg-opacity: .5}.bg-opacity-75{--tblr-bg-opacity: .75}.bg-opacity-100{--tblr-bg-opacity: 1}.bg-primary-subtle{background-color:var(--tblr-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--tblr-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--tblr-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--tblr-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--tblr-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--tblr-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--tblr-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--tblr-dark-bg-subtle)!important}.bg-gradient{background-image:var(--tblr-gradient)!important}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--tblr-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--tblr-border-radius-sm)!important}.rounded-2{border-radius:var(--tblr-border-radius)!important}.rounded-3{border-radius:var(--tblr-border-radius-lg)!important}.rounded-4{border-radius:var(--tblr-border-radius-xl)!important}.rounded-5{border-radius:var(--tblr-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--tblr-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--tblr-border-radius)!important;border-top-right-radius:var(--tblr-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--tblr-border-radius-sm)!important;border-top-right-radius:var(--tblr-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--tblr-border-radius)!important;border-top-right-radius:var(--tblr-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--tblr-border-radius-lg)!important;border-top-right-radius:var(--tblr-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--tblr-border-radius-xl)!important;border-top-right-radius:var(--tblr-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--tblr-border-radius-xxl)!important;border-top-right-radius:var(--tblr-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--tblr-border-radius-pill)!important;border-top-right-radius:var(--tblr-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--tblr-border-radius)!important;border-bottom-right-radius:var(--tblr-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--tblr-border-radius-sm)!important;border-bottom-right-radius:var(--tblr-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--tblr-border-radius)!important;border-bottom-right-radius:var(--tblr-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--tblr-border-radius-lg)!important;border-bottom-right-radius:var(--tblr-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--tblr-border-radius-xl)!important;border-bottom-right-radius:var(--tblr-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--tblr-border-radius-xxl)!important;border-bottom-right-radius:var(--tblr-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--tblr-border-radius-pill)!important;border-bottom-right-radius:var(--tblr-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--tblr-border-radius)!important;border-bottom-left-radius:var(--tblr-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--tblr-border-radius-sm)!important;border-bottom-left-radius:var(--tblr-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--tblr-border-radius)!important;border-bottom-left-radius:var(--tblr-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--tblr-border-radius-lg)!important;border-bottom-left-radius:var(--tblr-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--tblr-border-radius-xl)!important;border-bottom-left-radius:var(--tblr-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--tblr-border-radius-xxl)!important;border-bottom-left-radius:var(--tblr-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--tblr-border-radius-pill)!important;border-bottom-left-radius:var(--tblr-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--tblr-border-radius)!important;border-top-left-radius:var(--tblr-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--tblr-border-radius-sm)!important;border-top-left-radius:var(--tblr-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--tblr-border-radius)!important;border-top-left-radius:var(--tblr-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--tblr-border-radius-lg)!important;border-top-left-radius:var(--tblr-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--tblr-border-radius-xl)!important;border-top-left-radius:var(--tblr-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--tblr-border-radius-xxl)!important;border-top-left-radius:var(--tblr-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--tblr-border-radius-pill)!important;border-top-left-radius:var(--tblr-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}.object-contain{object-fit:contain!important}.object-cover{object-fit:cover!important}.object-fill{object-fit:fill!important}.object-scale-down{object-fit:scale-down!important}.object-none{object-fit:none!important}.cursor-auto{cursor:auto!important}.cursor-pointer{cursor:pointer!important}.cursor-move{cursor:move!important}.cursor-not-allowed{cursor:not-allowed!important}.cursor-zoom-in{cursor:zoom-in!important}.cursor-zoom-out{cursor:zoom-out!important}.cursor-default{cursor:default!important}.cursor-none{cursor:none!important}.cursor-help{cursor:help!important}.cursor-progress{cursor:progress!important}.cursor-wait{cursor:wait!important}.cursor-text{cursor:text!important}.cursor-v-text{cursor:vertical-text!important}.cursor-grab{cursor:grab!important}.cursor-grabbing{cursor:grabbing!important}.border-x{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important;border-right:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-x-wide{border-left:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important;border-right:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-x-0{border-left:0!important;border-right:0!important}.border-y{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important;border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-y-wide{border-top:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important;border-bottom:2px var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.border-y-0{border-top:0!important;border-bottom:0!important}.columns-2{columns:2!important}.columns-3{columns:3!important}.columns-4{columns:4!important}@media (min-width: 576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{object-fit:contain!important}.object-fit-sm-cover{object-fit:cover!important}.object-fit-sm-fill{object-fit:fill!important}.object-fit-sm-scale{object-fit:scale-down!important}.object-fit-sm-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:2rem!important}.m-sm-6{margin:2.5rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:2rem!important;margin-left:2rem!important}.mx-sm-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-sm-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:2rem!important}.mt-sm-6{margin-top:2.5rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:2rem!important}.me-sm-6{margin-right:2.5rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:2rem!important}.mb-sm-6{margin-bottom:2.5rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:2rem!important}.ms-sm-6{margin-left:2.5rem!important}.ms-sm-auto{margin-left:auto!important}.m-sm-n1{margin:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.m-sm-n3{margin:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.m-sm-n5{margin:-2rem!important}.m-sm-n6{margin:-2.5rem!important}.mx-sm-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-sm-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-sm-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-sm-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-sm-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-sm-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-sm-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-sm-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-sm-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-sm-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-sm-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-sm-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-sm-n1{margin-top:-.25rem!important}.mt-sm-n2{margin-top:-.5rem!important}.mt-sm-n3{margin-top:-1rem!important}.mt-sm-n4{margin-top:-1.5rem!important}.mt-sm-n5{margin-top:-2rem!important}.mt-sm-n6{margin-top:-2.5rem!important}.me-sm-n1{margin-right:-.25rem!important}.me-sm-n2{margin-right:-.5rem!important}.me-sm-n3{margin-right:-1rem!important}.me-sm-n4{margin-right:-1.5rem!important}.me-sm-n5{margin-right:-2rem!important}.me-sm-n6{margin-right:-2.5rem!important}.mb-sm-n1{margin-bottom:-.25rem!important}.mb-sm-n2{margin-bottom:-.5rem!important}.mb-sm-n3{margin-bottom:-1rem!important}.mb-sm-n4{margin-bottom:-1.5rem!important}.mb-sm-n5{margin-bottom:-2rem!important}.mb-sm-n6{margin-bottom:-2.5rem!important}.ms-sm-n1{margin-left:-.25rem!important}.ms-sm-n2{margin-left:-.5rem!important}.ms-sm-n3{margin-left:-1rem!important}.ms-sm-n4{margin-left:-1.5rem!important}.ms-sm-n5{margin-left:-2rem!important}.ms-sm-n6{margin-left:-2.5rem!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:2rem!important}.p-sm-6{padding:2.5rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:2rem!important;padding-left:2rem!important}.px-sm-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-sm-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:2rem!important}.pt-sm-6{padding-top:2.5rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:2rem!important}.pe-sm-6{padding-right:2.5rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:2rem!important}.pb-sm-6{padding-bottom:2.5rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:2rem!important}.ps-sm-6{padding-left:2.5rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:2rem!important}.gap-sm-6{gap:2.5rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:2rem!important}.row-gap-sm-6{row-gap:2.5rem!important}.column-gap-sm-0{column-gap:0!important}.column-gap-sm-1{column-gap:.25rem!important}.column-gap-sm-2{column-gap:.5rem!important}.column-gap-sm-3{column-gap:1rem!important}.column-gap-sm-4{column-gap:1.5rem!important}.column-gap-sm-5{column-gap:2rem!important}.column-gap-sm-6{column-gap:2.5rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}.columns-sm-2{columns:2!important}.columns-sm-3{columns:3!important}.columns-sm-4{columns:4!important}}@media (min-width: 768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{object-fit:contain!important}.object-fit-md-cover{object-fit:cover!important}.object-fit-md-fill{object-fit:fill!important}.object-fit-md-scale{object-fit:scale-down!important}.object-fit-md-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:2rem!important}.m-md-6{margin:2.5rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:2rem!important;margin-left:2rem!important}.mx-md-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-md-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:2rem!important}.mt-md-6{margin-top:2.5rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:2rem!important}.me-md-6{margin-right:2.5rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:2rem!important}.mb-md-6{margin-bottom:2.5rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:2rem!important}.ms-md-6{margin-left:2.5rem!important}.ms-md-auto{margin-left:auto!important}.m-md-n1{margin:-.25rem!important}.m-md-n2{margin:-.5rem!important}.m-md-n3{margin:-1rem!important}.m-md-n4{margin:-1.5rem!important}.m-md-n5{margin:-2rem!important}.m-md-n6{margin:-2.5rem!important}.mx-md-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-md-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-md-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-md-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-md-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-md-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-md-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-md-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-md-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-md-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-md-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-md-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-md-n1{margin-top:-.25rem!important}.mt-md-n2{margin-top:-.5rem!important}.mt-md-n3{margin-top:-1rem!important}.mt-md-n4{margin-top:-1.5rem!important}.mt-md-n5{margin-top:-2rem!important}.mt-md-n6{margin-top:-2.5rem!important}.me-md-n1{margin-right:-.25rem!important}.me-md-n2{margin-right:-.5rem!important}.me-md-n3{margin-right:-1rem!important}.me-md-n4{margin-right:-1.5rem!important}.me-md-n5{margin-right:-2rem!important}.me-md-n6{margin-right:-2.5rem!important}.mb-md-n1{margin-bottom:-.25rem!important}.mb-md-n2{margin-bottom:-.5rem!important}.mb-md-n3{margin-bottom:-1rem!important}.mb-md-n4{margin-bottom:-1.5rem!important}.mb-md-n5{margin-bottom:-2rem!important}.mb-md-n6{margin-bottom:-2.5rem!important}.ms-md-n1{margin-left:-.25rem!important}.ms-md-n2{margin-left:-.5rem!important}.ms-md-n3{margin-left:-1rem!important}.ms-md-n4{margin-left:-1.5rem!important}.ms-md-n5{margin-left:-2rem!important}.ms-md-n6{margin-left:-2.5rem!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:2rem!important}.p-md-6{padding:2.5rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:2rem!important;padding-left:2rem!important}.px-md-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-md-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:2rem!important}.pt-md-6{padding-top:2.5rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:2rem!important}.pe-md-6{padding-right:2.5rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:2rem!important}.pb-md-6{padding-bottom:2.5rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:2rem!important}.ps-md-6{padding-left:2.5rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:2rem!important}.gap-md-6{gap:2.5rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:2rem!important}.row-gap-md-6{row-gap:2.5rem!important}.column-gap-md-0{column-gap:0!important}.column-gap-md-1{column-gap:.25rem!important}.column-gap-md-2{column-gap:.5rem!important}.column-gap-md-3{column-gap:1rem!important}.column-gap-md-4{column-gap:1.5rem!important}.column-gap-md-5{column-gap:2rem!important}.column-gap-md-6{column-gap:2.5rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}.columns-md-2{columns:2!important}.columns-md-3{columns:3!important}.columns-md-4{columns:4!important}}@media (min-width: 992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{object-fit:contain!important}.object-fit-lg-cover{object-fit:cover!important}.object-fit-lg-fill{object-fit:fill!important}.object-fit-lg-scale{object-fit:scale-down!important}.object-fit-lg-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:2rem!important}.m-lg-6{margin:2.5rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:2rem!important;margin-left:2rem!important}.mx-lg-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-lg-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:2rem!important}.mt-lg-6{margin-top:2.5rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:2rem!important}.me-lg-6{margin-right:2.5rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:2rem!important}.mb-lg-6{margin-bottom:2.5rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:2rem!important}.ms-lg-6{margin-left:2.5rem!important}.ms-lg-auto{margin-left:auto!important}.m-lg-n1{margin:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.m-lg-n3{margin:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.m-lg-n5{margin:-2rem!important}.m-lg-n6{margin:-2.5rem!important}.mx-lg-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-lg-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-lg-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-lg-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-lg-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-lg-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-lg-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-lg-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-lg-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-lg-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-lg-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-lg-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-lg-n1{margin-top:-.25rem!important}.mt-lg-n2{margin-top:-.5rem!important}.mt-lg-n3{margin-top:-1rem!important}.mt-lg-n4{margin-top:-1.5rem!important}.mt-lg-n5{margin-top:-2rem!important}.mt-lg-n6{margin-top:-2.5rem!important}.me-lg-n1{margin-right:-.25rem!important}.me-lg-n2{margin-right:-.5rem!important}.me-lg-n3{margin-right:-1rem!important}.me-lg-n4{margin-right:-1.5rem!important}.me-lg-n5{margin-right:-2rem!important}.me-lg-n6{margin-right:-2.5rem!important}.mb-lg-n1{margin-bottom:-.25rem!important}.mb-lg-n2{margin-bottom:-.5rem!important}.mb-lg-n3{margin-bottom:-1rem!important}.mb-lg-n4{margin-bottom:-1.5rem!important}.mb-lg-n5{margin-bottom:-2rem!important}.mb-lg-n6{margin-bottom:-2.5rem!important}.ms-lg-n1{margin-left:-.25rem!important}.ms-lg-n2{margin-left:-.5rem!important}.ms-lg-n3{margin-left:-1rem!important}.ms-lg-n4{margin-left:-1.5rem!important}.ms-lg-n5{margin-left:-2rem!important}.ms-lg-n6{margin-left:-2.5rem!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:2rem!important}.p-lg-6{padding:2.5rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:2rem!important;padding-left:2rem!important}.px-lg-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-lg-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:2rem!important}.pt-lg-6{padding-top:2.5rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:2rem!important}.pe-lg-6{padding-right:2.5rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:2rem!important}.pb-lg-6{padding-bottom:2.5rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:2rem!important}.ps-lg-6{padding-left:2.5rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:2rem!important}.gap-lg-6{gap:2.5rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:2rem!important}.row-gap-lg-6{row-gap:2.5rem!important}.column-gap-lg-0{column-gap:0!important}.column-gap-lg-1{column-gap:.25rem!important}.column-gap-lg-2{column-gap:.5rem!important}.column-gap-lg-3{column-gap:1rem!important}.column-gap-lg-4{column-gap:1.5rem!important}.column-gap-lg-5{column-gap:2rem!important}.column-gap-lg-6{column-gap:2.5rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}.columns-lg-2{columns:2!important}.columns-lg-3{columns:3!important}.columns-lg-4{columns:4!important}}@media (min-width: 1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{object-fit:contain!important}.object-fit-xl-cover{object-fit:cover!important}.object-fit-xl-fill{object-fit:fill!important}.object-fit-xl-scale{object-fit:scale-down!important}.object-fit-xl-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:2rem!important}.m-xl-6{margin:2.5rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:2rem!important;margin-left:2rem!important}.mx-xl-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-xl-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:2rem!important}.mt-xl-6{margin-top:2.5rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:2rem!important}.me-xl-6{margin-right:2.5rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:2rem!important}.mb-xl-6{margin-bottom:2.5rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:2rem!important}.ms-xl-6{margin-left:2.5rem!important}.ms-xl-auto{margin-left:auto!important}.m-xl-n1{margin:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.m-xl-n3{margin:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.m-xl-n5{margin:-2rem!important}.m-xl-n6{margin:-2.5rem!important}.mx-xl-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-xl-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-xl-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-xl-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-xl-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-xl-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-xl-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-xl-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-xl-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-xl-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-xl-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-xl-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-xl-n1{margin-top:-.25rem!important}.mt-xl-n2{margin-top:-.5rem!important}.mt-xl-n3{margin-top:-1rem!important}.mt-xl-n4{margin-top:-1.5rem!important}.mt-xl-n5{margin-top:-2rem!important}.mt-xl-n6{margin-top:-2.5rem!important}.me-xl-n1{margin-right:-.25rem!important}.me-xl-n2{margin-right:-.5rem!important}.me-xl-n3{margin-right:-1rem!important}.me-xl-n4{margin-right:-1.5rem!important}.me-xl-n5{margin-right:-2rem!important}.me-xl-n6{margin-right:-2.5rem!important}.mb-xl-n1{margin-bottom:-.25rem!important}.mb-xl-n2{margin-bottom:-.5rem!important}.mb-xl-n3{margin-bottom:-1rem!important}.mb-xl-n4{margin-bottom:-1.5rem!important}.mb-xl-n5{margin-bottom:-2rem!important}.mb-xl-n6{margin-bottom:-2.5rem!important}.ms-xl-n1{margin-left:-.25rem!important}.ms-xl-n2{margin-left:-.5rem!important}.ms-xl-n3{margin-left:-1rem!important}.ms-xl-n4{margin-left:-1.5rem!important}.ms-xl-n5{margin-left:-2rem!important}.ms-xl-n6{margin-left:-2.5rem!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:2rem!important}.p-xl-6{padding:2.5rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:2rem!important;padding-left:2rem!important}.px-xl-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-xl-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:2rem!important}.pt-xl-6{padding-top:2.5rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:2rem!important}.pe-xl-6{padding-right:2.5rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:2rem!important}.pb-xl-6{padding-bottom:2.5rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:2rem!important}.ps-xl-6{padding-left:2.5rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:2rem!important}.gap-xl-6{gap:2.5rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:2rem!important}.row-gap-xl-6{row-gap:2.5rem!important}.column-gap-xl-0{column-gap:0!important}.column-gap-xl-1{column-gap:.25rem!important}.column-gap-xl-2{column-gap:.5rem!important}.column-gap-xl-3{column-gap:1rem!important}.column-gap-xl-4{column-gap:1.5rem!important}.column-gap-xl-5{column-gap:2rem!important}.column-gap-xl-6{column-gap:2.5rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}.columns-xl-2{columns:2!important}.columns-xl-3{columns:3!important}.columns-xl-4{columns:4!important}}@media (min-width: 1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{object-fit:contain!important}.object-fit-xxl-cover{object-fit:cover!important}.object-fit-xxl-fill{object-fit:fill!important}.object-fit-xxl-scale{object-fit:scale-down!important}.object-fit-xxl-none{object-fit: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-inline-grid{display:inline-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:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:2rem!important}.m-xxl-6{margin:2.5rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:2rem!important;margin-left:2rem!important}.mx-xxl-6{margin-right:2.5rem!important;margin-left:2.5rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:2rem!important;margin-bottom:2rem!important}.my-xxl-6{margin-top:2.5rem!important;margin-bottom:2.5rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:2rem!important}.mt-xxl-6{margin-top:2.5rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:2rem!important}.me-xxl-6{margin-right:2.5rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:2rem!important}.mb-xxl-6{margin-bottom:2.5rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:2rem!important}.ms-xxl-6{margin-left:2.5rem!important}.ms-xxl-auto{margin-left:auto!important}.m-xxl-n1{margin:-.25rem!important}.m-xxl-n2{margin:-.5rem!important}.m-xxl-n3{margin:-1rem!important}.m-xxl-n4{margin:-1.5rem!important}.m-xxl-n5{margin:-2rem!important}.m-xxl-n6{margin:-2.5rem!important}.mx-xxl-n1{margin-right:-.25rem!important;margin-left:-.25rem!important}.mx-xxl-n2{margin-right:-.5rem!important;margin-left:-.5rem!important}.mx-xxl-n3{margin-right:-1rem!important;margin-left:-1rem!important}.mx-xxl-n4{margin-right:-1.5rem!important;margin-left:-1.5rem!important}.mx-xxl-n5{margin-right:-2rem!important;margin-left:-2rem!important}.mx-xxl-n6{margin-right:-2.5rem!important;margin-left:-2.5rem!important}.my-xxl-n1{margin-top:-.25rem!important;margin-bottom:-.25rem!important}.my-xxl-n2{margin-top:-.5rem!important;margin-bottom:-.5rem!important}.my-xxl-n3{margin-top:-1rem!important;margin-bottom:-1rem!important}.my-xxl-n4{margin-top:-1.5rem!important;margin-bottom:-1.5rem!important}.my-xxl-n5{margin-top:-2rem!important;margin-bottom:-2rem!important}.my-xxl-n6{margin-top:-2.5rem!important;margin-bottom:-2.5rem!important}.mt-xxl-n1{margin-top:-.25rem!important}.mt-xxl-n2{margin-top:-.5rem!important}.mt-xxl-n3{margin-top:-1rem!important}.mt-xxl-n4{margin-top:-1.5rem!important}.mt-xxl-n5{margin-top:-2rem!important}.mt-xxl-n6{margin-top:-2.5rem!important}.me-xxl-n1{margin-right:-.25rem!important}.me-xxl-n2{margin-right:-.5rem!important}.me-xxl-n3{margin-right:-1rem!important}.me-xxl-n4{margin-right:-1.5rem!important}.me-xxl-n5{margin-right:-2rem!important}.me-xxl-n6{margin-right:-2.5rem!important}.mb-xxl-n1{margin-bottom:-.25rem!important}.mb-xxl-n2{margin-bottom:-.5rem!important}.mb-xxl-n3{margin-bottom:-1rem!important}.mb-xxl-n4{margin-bottom:-1.5rem!important}.mb-xxl-n5{margin-bottom:-2rem!important}.mb-xxl-n6{margin-bottom:-2.5rem!important}.ms-xxl-n1{margin-left:-.25rem!important}.ms-xxl-n2{margin-left:-.5rem!important}.ms-xxl-n3{margin-left:-1rem!important}.ms-xxl-n4{margin-left:-1.5rem!important}.ms-xxl-n5{margin-left:-2rem!important}.ms-xxl-n6{margin-left:-2.5rem!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:2rem!important}.p-xxl-6{padding:2.5rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:2rem!important;padding-left:2rem!important}.px-xxl-6{padding-right:2.5rem!important;padding-left:2.5rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:2rem!important;padding-bottom:2rem!important}.py-xxl-6{padding-top:2.5rem!important;padding-bottom:2.5rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:2rem!important}.pt-xxl-6{padding-top:2.5rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:2rem!important}.pe-xxl-6{padding-right:2.5rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:2rem!important}.pb-xxl-6{padding-bottom:2.5rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:2rem!important}.ps-xxl-6{padding-left:2.5rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:2rem!important}.gap-xxl-6{gap:2.5rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:2rem!important}.row-gap-xxl-6{row-gap:2.5rem!important}.column-gap-xxl-0{column-gap:0!important}.column-gap-xxl-1{column-gap:.25rem!important}.column-gap-xxl-2{column-gap:.5rem!important}.column-gap-xxl-3{column-gap:1rem!important}.column-gap-xxl-4{column-gap:1.5rem!important}.column-gap-xxl-5{column-gap:2rem!important}.column-gap-xxl-6{column-gap:2.5rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}.columns-xxl-2{columns:2!important}.columns-xxl-3{columns:3!important}.columns-xxl-4{columns:4!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-inline-grid{display:inline-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}}:root,:host{font-size:16px;height:100%}:root,:host,[data-bs-theme=light]{--tblr-primary: #00857D;--tblr-primary-rgb: 0, 133, 125;--tblr-primary-fg: var(--tblr-light);--tblr-primary-darken: #007871;--tblr-primary-lt: #e6f3f2;--tblr-primary-lt-rgb: 230, 243, 242;--tblr-secondary: #6c7a91;--tblr-secondary-rgb: 108, 122, 145;--tblr-secondary-fg: var(--tblr-light);--tblr-secondary-darken: #616e83;--tblr-secondary-lt: #f0f2f4;--tblr-secondary-lt-rgb: 240, 242, 244;--tblr-success: #2fb344;--tblr-success-rgb: 47, 179, 68;--tblr-success-fg: var(--tblr-light);--tblr-success-darken: #2aa13d;--tblr-success-lt: #eaf7ec;--tblr-success-lt-rgb: 234, 247, 236;--tblr-info: #4299e1;--tblr-info-rgb: 66, 153, 225;--tblr-info-fg: var(--tblr-light);--tblr-info-darken: #3b8acb;--tblr-info-lt: #ecf5fc;--tblr-info-lt-rgb: 236, 245, 252;--tblr-warning: #f76707;--tblr-warning-rgb: 247, 103, 7;--tblr-warning-fg: var(--tblr-light);--tblr-warning-darken: #de5d06;--tblr-warning-lt: #fef0e6;--tblr-warning-lt-rgb: 254, 240, 230;--tblr-danger: #d63939;--tblr-danger-rgb: 214, 57, 57;--tblr-danger-fg: var(--tblr-light);--tblr-danger-darken: #c13333;--tblr-danger-lt: #fbebeb;--tblr-danger-lt-rgb: 251, 235, 235;--tblr-light: #f6f8fb;--tblr-light-rgb: 246, 248, 251;--tblr-light-fg: var(--tblr-dark);--tblr-light-darken: #dddfe2;--tblr-light-lt: #fefeff;--tblr-light-lt-rgb: 254, 254, 255;--tblr-dark: #182433;--tblr-dark-rgb: 24, 36, 51;--tblr-dark-fg: var(--tblr-light);--tblr-dark-darken: #16202e;--tblr-dark-lt: #e8e9eb;--tblr-dark-lt-rgb: 232, 233, 235;--tblr-muted: #6c7a91;--tblr-muted-rgb: 108, 122, 145;--tblr-muted-fg: var(--tblr-light);--tblr-muted-darken: #616e83;--tblr-muted-lt: #f0f2f4;--tblr-muted-lt-rgb: 240, 242, 244;--tblr-blue: #066fd1;--tblr-blue-rgb: 6, 111, 209;--tblr-blue-fg: var(--tblr-light);--tblr-blue-darken: #0564bc;--tblr-blue-lt: #e6f1fa;--tblr-blue-lt-rgb: 230, 241, 250;--tblr-azure: #4299e1;--tblr-azure-rgb: 66, 153, 225;--tblr-azure-fg: var(--tblr-light);--tblr-azure-darken: #3b8acb;--tblr-azure-lt: #ecf5fc;--tblr-azure-lt-rgb: 236, 245, 252;--tblr-indigo: #4263eb;--tblr-indigo-rgb: 66, 99, 235;--tblr-indigo-fg: var(--tblr-light);--tblr-indigo-darken: #3b59d4;--tblr-indigo-lt: #eceffd;--tblr-indigo-lt-rgb: 236, 239, 253;--tblr-purple: #ae3ec9;--tblr-purple-rgb: 174, 62, 201;--tblr-purple-fg: var(--tblr-light);--tblr-purple-darken: #9d38b5;--tblr-purple-lt: #f7ecfa;--tblr-purple-lt-rgb: 247, 236, 250;--tblr-pink: #d6336c;--tblr-pink-rgb: 214, 51, 108;--tblr-pink-fg: var(--tblr-light);--tblr-pink-darken: #c12e61;--tblr-pink-lt: #fbebf0;--tblr-pink-lt-rgb: 251, 235, 240;--tblr-red: #d63939;--tblr-red-rgb: 214, 57, 57;--tblr-red-fg: var(--tblr-light);--tblr-red-darken: #c13333;--tblr-red-lt: #fbebeb;--tblr-red-lt-rgb: 251, 235, 235;--tblr-orange: #f76707;--tblr-orange-rgb: 247, 103, 7;--tblr-orange-fg: var(--tblr-light);--tblr-orange-darken: #de5d06;--tblr-orange-lt: #fef0e6;--tblr-orange-lt-rgb: 254, 240, 230;--tblr-yellow: #f59f00;--tblr-yellow-rgb: 245, 159, 0;--tblr-yellow-fg: var(--tblr-light);--tblr-yellow-darken: #dd8f00;--tblr-yellow-lt: #fef5e6;--tblr-yellow-lt-rgb: 254, 245, 230;--tblr-lime: #74b816;--tblr-lime-rgb: 116, 184, 22;--tblr-lime-fg: var(--tblr-light);--tblr-lime-darken: #68a614;--tblr-lime-lt: #f1f8e8;--tblr-lime-lt-rgb: 241, 248, 232;--tblr-green: #2fb344;--tblr-green-rgb: 47, 179, 68;--tblr-green-fg: var(--tblr-light);--tblr-green-darken: #2aa13d;--tblr-green-lt: #eaf7ec;--tblr-green-lt-rgb: 234, 247, 236;--tblr-teal: #0ca678;--tblr-teal-rgb: 12, 166, 120;--tblr-teal-fg: var(--tblr-light);--tblr-teal-darken: #0b956c;--tblr-teal-lt: #e7f6f2;--tblr-teal-lt-rgb: 231, 246, 242;--tblr-cyan: #17a2b8;--tblr-cyan-rgb: 23, 162, 184;--tblr-cyan-fg: var(--tblr-light);--tblr-cyan-darken: #1592a6;--tblr-cyan-lt: #e8f6f8;--tblr-cyan-lt-rgb: 232, 246, 248;--tblr-x: #000000;--tblr-x-rgb: 0, 0, 0;--tblr-x-fg: var(--tblr-light);--tblr-x-darken: black;--tblr-x-lt: #e6e6e6;--tblr-x-lt-rgb: 230, 230, 230;--tblr-facebook: #1877f2;--tblr-facebook-rgb: 24, 119, 242;--tblr-facebook-fg: var(--tblr-light);--tblr-facebook-darken: #166bda;--tblr-facebook-lt: #e8f1fe;--tblr-facebook-lt-rgb: 232, 241, 254;--tblr-twitter: #1da1f2;--tblr-twitter-rgb: 29, 161, 242;--tblr-twitter-fg: var(--tblr-light);--tblr-twitter-darken: #1a91da;--tblr-twitter-lt: #e8f6fe;--tblr-twitter-lt-rgb: 232, 246, 254;--tblr-linkedin: #0a66c2;--tblr-linkedin-rgb: 10, 102, 194;--tblr-linkedin-fg: var(--tblr-light);--tblr-linkedin-darken: #095caf;--tblr-linkedin-lt: #e7f0f9;--tblr-linkedin-lt-rgb: 231, 240, 249;--tblr-google: #dc4e41;--tblr-google-rgb: 220, 78, 65;--tblr-google-fg: var(--tblr-light);--tblr-google-darken: #c6463b;--tblr-google-lt: #fcedec;--tblr-google-lt-rgb: 252, 237, 236;--tblr-youtube: #ff0000;--tblr-youtube-rgb: 255, 0, 0;--tblr-youtube-fg: var(--tblr-light);--tblr-youtube-darken: #e60000;--tblr-youtube-lt: #ffe6e6;--tblr-youtube-lt-rgb: 255, 230, 230;--tblr-vimeo: #1ab7ea;--tblr-vimeo-rgb: 26, 183, 234;--tblr-vimeo-fg: var(--tblr-light);--tblr-vimeo-darken: #17a5d3;--tblr-vimeo-lt: #e8f8fd;--tblr-vimeo-lt-rgb: 232, 248, 253;--tblr-dribbble: #ea4c89;--tblr-dribbble-rgb: 234, 76, 137;--tblr-dribbble-fg: var(--tblr-light);--tblr-dribbble-darken: #d3447b;--tblr-dribbble-lt: #fdedf3;--tblr-dribbble-lt-rgb: 253, 237, 243;--tblr-github: #181717;--tblr-github-rgb: 24, 23, 23;--tblr-github-fg: var(--tblr-light);--tblr-github-darken: #161515;--tblr-github-lt: #e8e8e8;--tblr-github-lt-rgb: 232, 232, 232;--tblr-instagram: #e4405f;--tblr-instagram-rgb: 228, 64, 95;--tblr-instagram-fg: var(--tblr-light);--tblr-instagram-darken: #cd3a56;--tblr-instagram-lt: #fcecef;--tblr-instagram-lt-rgb: 252, 236, 239;--tblr-pinterest: #bd081c;--tblr-pinterest-rgb: 189, 8, 28;--tblr-pinterest-fg: var(--tblr-light);--tblr-pinterest-darken: #aa0719;--tblr-pinterest-lt: #f8e6e8;--tblr-pinterest-lt-rgb: 248, 230, 232;--tblr-vk: #6383a8;--tblr-vk-rgb: 99, 131, 168;--tblr-vk-fg: var(--tblr-light);--tblr-vk-darken: #597697;--tblr-vk-lt: #eff3f6;--tblr-vk-lt-rgb: 239, 243, 246;--tblr-rss: #ffa500;--tblr-rss-rgb: 255, 165, 0;--tblr-rss-fg: var(--tblr-light);--tblr-rss-darken: #e69500;--tblr-rss-lt: #fff6e6;--tblr-rss-lt-rgb: 255, 246, 230;--tblr-flickr: #0063dc;--tblr-flickr-rgb: 0, 99, 220;--tblr-flickr-fg: var(--tblr-light);--tblr-flickr-darken: #0059c6;--tblr-flickr-lt: #e6effc;--tblr-flickr-lt-rgb: 230, 239, 252;--tblr-bitbucket: #0052cc;--tblr-bitbucket-rgb: 0, 82, 204;--tblr-bitbucket-fg: var(--tblr-light);--tblr-bitbucket-darken: #004ab8;--tblr-bitbucket-lt: #e6eefa;--tblr-bitbucket-lt-rgb: 230, 238, 250;--tblr-tabler: #066fd1;--tblr-tabler-rgb: 6, 111, 209;--tblr-tabler-fg: var(--tblr-light);--tblr-tabler-darken: #0564bc;--tblr-tabler-lt: #e6f1fa;--tblr-tabler-lt-rgb: 230, 241, 250;--tblr-gray-50: #f6f8fb;--tblr-gray-50-rgb: 246, 248, 251;--tblr-gray-50-fg: var(--tblr-dark);--tblr-gray-50-darken: #dddfe2;--tblr-gray-50-lt: #fefeff;--tblr-gray-50-lt-rgb: 254, 254, 255;--tblr-gray-100: #eef3f6;--tblr-gray-100-rgb: 238, 243, 246;--tblr-gray-100-fg: var(--tblr-dark);--tblr-gray-100-darken: #d6dbdd;--tblr-gray-100-lt: #fdfefe;--tblr-gray-100-lt-rgb: 253, 254, 254;--tblr-gray-200: #dce1e7;--tblr-gray-200-rgb: 220, 225, 231;--tblr-gray-200-fg: var(--tblr-dark);--tblr-gray-200-darken: #c6cbd0;--tblr-gray-200-lt: #fcfcfd;--tblr-gray-200-lt-rgb: 252, 252, 253;--tblr-gray-300: #b8c4d4;--tblr-gray-300-rgb: 184, 196, 212;--tblr-gray-300-fg: var(--tblr-light);--tblr-gray-300-darken: #a6b0bf;--tblr-gray-300-lt: #f8f9fb;--tblr-gray-300-lt-rgb: 248, 249, 251;--tblr-gray-400: #8a97ab;--tblr-gray-400-rgb: 138, 151, 171;--tblr-gray-400-fg: var(--tblr-light);--tblr-gray-400-darken: #7c889a;--tblr-gray-400-lt: #f3f5f7;--tblr-gray-400-lt-rgb: 243, 245, 247;--tblr-gray-500: #6c7a91;--tblr-gray-500-rgb: 108, 122, 145;--tblr-gray-500-fg: var(--tblr-light);--tblr-gray-500-darken: #616e83;--tblr-gray-500-lt: #f0f2f4;--tblr-gray-500-lt-rgb: 240, 242, 244;--tblr-gray-600: #49566c;--tblr-gray-600-rgb: 73, 86, 108;--tblr-gray-600-fg: var(--tblr-light);--tblr-gray-600-darken: #424d61;--tblr-gray-600-lt: #edeef0;--tblr-gray-600-lt-rgb: 237, 238, 240;--tblr-gray-700: #3a4859;--tblr-gray-700-rgb: 58, 72, 89;--tblr-gray-700-fg: var(--tblr-light);--tblr-gray-700-darken: #344150;--tblr-gray-700-lt: #ebedee;--tblr-gray-700-lt-rgb: 235, 237, 238;--tblr-gray-800: #182433;--tblr-gray-800-rgb: 24, 36, 51;--tblr-gray-800-fg: var(--tblr-light);--tblr-gray-800-darken: #16202e;--tblr-gray-800-lt: #e8e9eb;--tblr-gray-800-lt-rgb: 232, 233, 235;--tblr-gray-900: #040a11;--tblr-gray-900-rgb: 4, 10, 17;--tblr-gray-900-fg: var(--tblr-light);--tblr-gray-900-darken: #04090f;--tblr-gray-900-lt: #e6e7e7;--tblr-gray-900-lt-rgb: 230, 231, 231;--tblr-spacer-0: 0;--tblr-spacer-1: .25rem;--tblr-spacer-2: .5rem;--tblr-spacer-3: 1rem;--tblr-spacer-4: 1.5rem;--tblr-spacer-5: 2rem;--tblr-spacer-6: 2.5rem;--tblr-spacer: 1rem;--tblr-bg-surface: var(--tblr-white);--tblr-bg-surface-secondary: var(--tblr-gray-100);--tblr-bg-surface-tertiary: var(--tblr-gray-50);--tblr-bg-surface-dark: var(--tblr-dark);--tblr-bg-forms: var(--tblr-bg-surface);--tblr-border-color: #dce1e7;--tblr-border-color-translucent: rgba(4, 32, 69, .1);--tblr-border-dark-color: #8a97ab;--tblr-border-dark-color-translucent: rgba(4, 32, 69, .27);--tblr-border-active-color: #aab2bf;--tblr-icon-color: var(--tblr-gray-400);--tblr-active-bg: rgba(var(--tblr-primary-rgb), .04);--tblr-disabled-bg: var(--tblr-bg-surface-secondary);--tblr-disabled-color: var(--tblr-gray-300);--tblr-code-color: var(--tblr-gray-600);--tblr-code-bg: var(--tblr-bg-surface-secondary);--tblr-dark-mode-border-color: #25384f;--tblr-dark-mode-border-color-translucent: rgba(72, 110, 149, .14);--tblr-dark-mode-border-active-color: #2c415d;--tblr-dark-mode-border-dark-color: #1f2e41;--tblr-page-padding: var(--tblr-spacer-3);--tblr-page-padding-y: var(--tblr-spacer-4);--tblr-font-weight-light: 300;--tblr-font-weight-normal: 400;--tblr-font-weight-medium: 500;--tblr-font-weight-bold: 600;--tblr-font-weight-black: 700;--tblr-font-weight-headings: var(--tblr-font-weight-bold);--tblr-font-size-h1: 1.5rem;--tblr-font-size-h2: 1.25rem;--tblr-font-size-h3: 1rem;--tblr-font-size-h4: .875rem;--tblr-font-size-h5: .75rem;--tblr-font-size-h6: .625rem;--tblr-line-height-h1: 2rem;--tblr-line-height-h2: 1.75rem;--tblr-line-height-h3: 1.5rem;--tblr-line-height-h4: 1.25rem;--tblr-line-height-h5: 1rem;--tblr-line-height-h6: 1rem;--tblr-box-shadow: rgba(var(--tblr-body-color-rgb), .04) 0 2px 4px 0;--tblr-box-shadow-border: inset 0 0 0 1px var(--tblr-border-color-translucent);--tblr-box-shadow-transparent: 0 0 0 0 transparent;--tblr-box-shadow-input: 0 1px 1px rgba(var(--tblr-body-color-rgb), .06);--tblr-box-shadow-card: 0 0 4px rgba(var(--tblr-body-color-rgb), .04);--tblr-box-shadow-card-hover: rgba(var(--tblr-body-color-rgb), .16) 0 2px 16px 0;--tblr-box-shadow-dropdown: 0 16px 24px 2px rgba(0, 0, 0, .07), 0 6px 30px 5px rgba(0, 0, 0, .06), 0 8px 10px -5px rgba(0, 0, 0, .1)}@media (max-width: 991.98px){:root,:host,[data-bs-theme=light]{--tblr-page-padding: var(--tblr-spacer-2)}}@keyframes pulse{0%{opacity:1;transform:scale3d(.8,.8,.8)}50%{transform:scaleZ(1);opacity:1}to{opacity:1;transform:scale3d(.8,.8,.8)}}@keyframes tada{0%{transform:scaleZ(1)}10%,5%{transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-5deg)}15%,25%,35%,45%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,5deg)}20%,30%,40%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-5deg)}50%{transform:scaleZ(1)}}@keyframes rotate-360{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes blink{0%{opacity:0}50%{opacity:1}to{opacity:0}}body{letter-spacing:0;touch-action:manipulation;text-rendering:optimizeLegibility;font-feature-settings:"liga" 0,"cv03","cv04","cv11";position:relative;min-height:100%;height:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media print{body{background:transparent}}*{scrollbar-color:rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}*::-webkit-scrollbar{width:1rem;height:1rem;transition:background .3s}@media (prefers-reduced-motion: reduce){*::-webkit-scrollbar{transition:none}}*::-webkit-scrollbar-thumb{border-radius:1rem;border:5px solid transparent;box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}*::-webkit-scrollbar-track{background:transparent}*:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.32)}*::-webkit-scrollbar-corner{background:transparent}.layout-fluid .container,.layout-fluid [class^=container-],.layout-fluid [class*=" container-"]{max-width:100%}.layout-boxed{--tblr-theme-boxed-border-radius: 0;--tblr-theme-boxed-width: 1320px}@media (min-width: 768px){.layout-boxed{background:#182433 linear-gradient(to right,rgba(255,255,255,.1),transparent) fixed;padding:1rem;--tblr-theme-boxed-border-radius: 4px}}.layout-boxed .page{margin:0 auto;max-width:var(--tblr-theme-boxed-width);border-radius:var(--tblr-theme-boxed-border-radius);color:var(--tblr-body-color)}@media (min-width: 768px){.layout-boxed .page{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);background:var(--tblr-body-bg)}}.layout-boxed .page>.navbar:first-child{border-top-left-radius:var(--tblr-theme-boxed-border-radius);border-top-right-radius:var(--tblr-theme-boxed-border-radius)}.navbar{--tblr-navbar-bg: var(--tblr-bg-surface);--tblr-navbar-border-width: var(--tblr-border-width);--tblr-navbar-active-border-color: #00857D;--tblr-navbar-active-bg: rgba(0, 0, 0, .2);--tblr-navbar-border-color: var(--tblr-border-color);align-items:stretch;min-height:3.5rem;box-shadow:inset 0 calc(-1 * var(--tblr-navbar-border-width)) 0 0 var(--tblr-navbar-border-color);background:var(--tblr-navbar-bg);color:var(--tblr-navbar-color)}.navbar-collapse .navbar{flex-grow:1}.navbar.collapsing{min-height:0}.navbar .dropdown-menu{position:absolute;z-index:1030}.navbar .navbar-nav{min-height:3rem}.navbar .navbar-nav .nav-link{position:relative;min-width:2rem;min-height:2rem;justify-content:center;border-radius:var(--tblr-border-radius)}.navbar .navbar-nav .nav-link .badge{position:absolute;top:.375rem;right:.375rem;transform:translate(50%,-50%)}.navbar-nav{margin:0;padding:0}@media (max-width: 575.98px){.navbar-expand-sm .navbar-collapse{flex-direction:column}.navbar-expand-sm .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-sm .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-sm .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-sm .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-sm .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-sm .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-sm .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 576px){.navbar-expand-sm .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-sm .nav-item.active{position:relative}.navbar-expand-sm .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-sm.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-sm.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-sm.navbar-vertical~.navbar,.navbar-expand-sm.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-sm.navbar-vertical.navbar-right~.navbar,.navbar-expand-sm.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 767.98px){.navbar-expand-md .navbar-collapse{flex-direction:column}.navbar-expand-md .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-md .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-md .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-md .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-md .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-md .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-md .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 768px){.navbar-expand-md .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-md .nav-item.active{position:relative}.navbar-expand-md .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-md.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-md.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-md.navbar-vertical~.navbar,.navbar-expand-md.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-md.navbar-vertical.navbar-right~.navbar,.navbar-expand-md.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 991.98px){.navbar-expand-lg .navbar-collapse{flex-direction:column}.navbar-expand-lg .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-lg .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-lg .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-lg .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-lg .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-lg .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-lg .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 992px){.navbar-expand-lg .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-lg .nav-item.active{position:relative}.navbar-expand-lg .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-lg.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-lg.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-lg.navbar-vertical~.navbar,.navbar-expand-lg.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-lg.navbar-vertical.navbar-right~.navbar,.navbar-expand-lg.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 1199.98px){.navbar-expand-xl .navbar-collapse{flex-direction:column}.navbar-expand-xl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-xl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-xl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-xl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-xl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-xl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-xl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1200px){.navbar-expand-xl .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-xl .nav-item.active{position:relative}.navbar-expand-xl .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-xl.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xl.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xl.navbar-vertical~.navbar,.navbar-expand-xl.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-xl.navbar-vertical.navbar-right~.navbar,.navbar-expand-xl.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}@media (max-width: 1399.98px){.navbar-expand-xxl .navbar-collapse{flex-direction:column}.navbar-expand-xxl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand-xxl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand-xxl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand-xxl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand-xxl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand-xxl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand-xxl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1400px){.navbar-expand-xxl .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand-xxl .nav-item.active{position:relative}.navbar-expand-xxl .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand-xxl.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xxl.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand-xxl.navbar-vertical~.navbar,.navbar-expand-xxl.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand-xxl.navbar-vertical.navbar-right~.navbar,.navbar-expand-xxl.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}}.navbar-expand .navbar-collapse{flex-direction:column}.navbar-expand .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-expand .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-expand .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-expand .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-expand .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-expand .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-expand .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}.navbar-expand .navbar-collapse{width:auto;flex:1 1 auto}.navbar-expand .nav-item.active{position:relative}.navbar-expand .nav-item.active:after{content:"";position:absolute;left:0;right:0;bottom:-.25rem;border:0 var(--tblr-border-style) var(--tblr-navbar-active-border-color);border-bottom-width:2px}.navbar-expand.navbar-vertical{box-shadow:inset calc(-1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand.navbar-vertical.navbar-right{box-shadow:inset calc(1 * var(--tblr-navbar-border-width)) 0 0 0 var(--tblr-navbar-border-color)}.navbar-expand.navbar-vertical~.navbar,.navbar-expand.navbar-vertical~.page-wrapper{margin-left:18rem}.navbar-expand.navbar-vertical.navbar-right~.navbar,.navbar-expand.navbar-vertical.navbar-right~.page-wrapper{margin-left:0;margin-right:18rem}.navbar-brand{display:inline-flex;align-items:center;font-weight:var(--tblr-font-weight-bold);margin:0;line-height:1;gap:.5rem}.navbar-brand-image{height:2rem;width:auto}.navbar-toggler{border:0;width:2rem;height:2rem;position:relative;display:flex;align-items:center;justify-content:center}.navbar-toggler-icon{height:2px;width:1.25em;background:currentColor;border-radius:10px;transition:top .2s .2s,bottom .2s .2s,transform .2s,opacity 0s .2s;position:relative}@media (prefers-reduced-motion: reduce){.navbar-toggler-icon{transition:none}}.navbar-toggler-icon:before,.navbar-toggler-icon:after{content:"";display:block;height:inherit;width:inherit;border-radius:inherit;background:inherit;position:absolute;left:0;transition:inherit}@media (prefers-reduced-motion: reduce){.navbar-toggler-icon:before,.navbar-toggler-icon:after{transition:none}}.navbar-toggler-icon:before{top:-.45em}.navbar-toggler-icon:after{bottom:-.45em}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon{transform:rotate(45deg);transition:top .3s,bottom .3s,transform .3s .3s,opacity 0s .3s}@media (prefers-reduced-motion: reduce){.navbar-toggler[aria-expanded=true] .navbar-toggler-icon{transition:none}}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon:before{top:0;transform:rotate(-90deg)}.navbar-toggler[aria-expanded=true] .navbar-toggler-icon:after{bottom:0;opacity:0}.navbar-transparent{--tblr-navbar-border-color: transparent !important;background:transparent!important}.navbar-nav{align-items:stretch}.navbar-nav .nav-item{display:flex;flex-direction:column;justify-content:center}.navbar-side{margin:0;display:flex;flex-direction:row;align-items:center;justify-content:space-around}@media (min-width: 576px){.navbar-vertical.navbar-expand-sm{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 576px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-sm{transition:none}}@media (min-width: 576px){.navbar-vertical.navbar-expand-sm.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-sm .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-sm .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-sm .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-sm>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-sm~.page{padding-left:18rem}.navbar-vertical.navbar-expand-sm~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-sm.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-sm .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-sm .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-sm .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-sm .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 768px){.navbar-vertical.navbar-expand-md{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 768px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-md{transition:none}}@media (min-width: 768px){.navbar-vertical.navbar-expand-md.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-md .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-md .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-md .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-md .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-md>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-md~.page{padding-left:18rem}.navbar-vertical.navbar-expand-md~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-md.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-md .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-md .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-md .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-md .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-md .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-md .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 992px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-lg{transition:none}}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-lg .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-lg .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-lg .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-lg>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-lg~.page{padding-left:18rem}.navbar-vertical.navbar-expand-lg~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-lg.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-lg .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-lg .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1200px){.navbar-vertical.navbar-expand-xl{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 1200px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-xl{transition:none}}@media (min-width: 1200px){.navbar-vertical.navbar-expand-xl.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-xl .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-xl .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-xl .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-xl>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-xl~.page{padding-left:18rem}.navbar-vertical.navbar-expand-xl~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-xl.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-xl .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-xl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-xl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-xl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}@media (min-width: 1400px){.navbar-vertical.navbar-expand-xxl{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}}@media (min-width: 1400px) and (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand-xxl{transition:none}}@media (min-width: 1400px){.navbar-vertical.navbar-expand-xxl.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand-xxl .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand-xxl .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand-xxl .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand-xxl>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand-xxl~.page{padding-left:18rem}.navbar-vertical.navbar-expand-xxl~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand-xxl.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand-xxl .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand-xxl .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand-xxl .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand-xxl .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}}.navbar-vertical.navbar-expand{width:18rem;position:fixed;top:0;left:0;bottom:0;z-index:1030;align-items:flex-start;transition:transform .3s;overflow-y:scroll;padding:0}@media (prefers-reduced-motion: reduce){.navbar-vertical.navbar-expand{transition:none}}.navbar-vertical.navbar-expand.navbar-right{left:auto;right:0}.navbar-vertical.navbar-expand .navbar-brand{padding:.75rem 0;justify-content:center}.navbar-vertical.navbar-expand .navbar-collapse{align-items:stretch}.navbar-vertical.navbar-expand .navbar-nav{flex-direction:column;flex-grow:1;min-height:auto}.navbar-vertical.navbar-expand .navbar-nav .nav-link{padding-top:.5rem;padding-bottom:.5rem}.navbar-vertical.navbar-expand>[class^=container]{flex-direction:column;align-items:stretch;min-height:100%;justify-content:flex-start;padding:0}.navbar-vertical.navbar-expand~.page{padding-left:18rem}.navbar-vertical.navbar-expand~.page [class^=container]{padding-left:1.5rem;padding-right:1.5rem}.navbar-vertical.navbar-expand.navbar-right~.page{padding-left:0;padding-right:18rem}.navbar-vertical.navbar-expand .navbar-collapse{flex-direction:column}.navbar-vertical.navbar-expand .navbar-collapse [class^=container]{flex-direction:column;align-items:stretch;padding:0}.navbar-vertical.navbar-expand .navbar-collapse .navbar-nav{margin-left:0;margin-right:0}.navbar-vertical.navbar-expand .navbar-collapse .navbar-nav .nav-link{padding:.5rem calc(calc(var(--tblr-page-padding) * 2) / 2);justify-content:flex-start}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu-columns{flex-direction:column}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu{padding:0;background:transparent;position:static;color:inherit;box-shadow:none;border:none;min-width:0;margin:0}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item{min-width:0;display:flex;width:auto;padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 1.75rem);color:inherit}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.disabled{color:var(--tblr-disabled-color);pointer-events:none;background-color:transparent}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item.active,.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-item:active{background:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 3.25rem)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-menu .dropdown-menu .dropdown-menu .dropdown-item{padding-left:calc(calc(calc(var(--tblr-page-padding) * 2) / 2) + 4.75rem)}.navbar-vertical.navbar-expand .navbar-collapse .dropdown-toggle:after{margin-left:auto}.navbar-vertical.navbar-expand .navbar-collapse .nav-item.active:after{border-bottom-width:0;border-left-width:3px;right:auto;top:0;bottom:0}.navbar-overlap:after{content:"";height:9rem;position:absolute;top:100%;left:0;right:0;background:inherit;z-index:-1;box-shadow:inherit}.page{display:flex;flex-direction:column;position:relative;min-height:100%}.page-center{justify-content:center}.page-wrapper{flex:1;display:flex;flex-direction:column}@media print{.page-wrapper{margin:0!important}}.page-wrapper-full .page-body:first-child{margin:0;border-top:0}.page-body{margin-top:var(--tblr-page-padding-y);margin-bottom:var(--tblr-page-padding-y);display:flex;flex-direction:column;flex:1}.page-body-card{background:var(--tblr-bg-surface);border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);padding:var(--tblr-page-padding) 0;margin-bottom:0;flex:1}.page-body~.page-body-card{margin-top:0}.page-cover{background:no-repeat center/cover;min-height:9rem}@media (min-width: 768px){.page-cover{min-height:12rem}}@media (min-width: 992px){.page-cover{min-height:15rem}}.page-cover-overlay{position:relative}.page-cover-overlay:after{content:"";position:absolute;inset:0;background-image:linear-gradient(180deg,#0000,#0009)}.page-header{display:flex;flex-wrap:wrap;min-height:2.25rem;flex-direction:column;justify-content:center}.page-wrapper .page-header{margin:var(--tblr-page-padding-y) 0 0}.page-header-border{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);padding:var(--tblr-page-padding-y) 0;margin:0!important;background-color:var(--tblr-bg-surface)}.page-pretitle{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary)}.page-title{margin:0;font-size:var(--tblr-font-size-h2);line-height:var(--tblr-line-height-h2);font-weight:var(--tblr-font-weight-headings);color:inherit;display:flex;align-items:center}.page-title svg{width:1.5rem;height:1.5rem;margin-right:.25rem}.page-title-lg{font-size:1.5rem;line-height:2rem}.page-subtitle{margin-top:.25rem;color:var(--tblr-secondary)}.page-cover{--tblr-page-cover-blur: 20px;--tblr-page-cover-padding: 1rem;min-height:6rem;padding:var(--tblr-page-cover-padding) 0;position:relative;overflow:hidden}.page-cover-img{position:absolute;top:calc(-2 * var(--tblr-page-cover-blur, 0));left:calc(-2 * var(--tblr-page-cover-blur, 0));right:calc(-2 * var(--tblr-page-cover-blur, 0));bottom:calc(-2 * var(--tblr-page-cover-blur, 0));pointer-events:none;filter:blur(var(--tblr-page-cover-blur));object-fit:cover;background-size:cover;background-position:center;z-index:-1}.page-tabs{margin-top:.5rem;position:relative}.page-header-tabs .nav-bordered{border:0}.page-header-tabs+.page-body-card{margin-top:0}.footer{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);background-color:#fff;padding:2rem 0;color:var(--tblr-gray-500);margin-top:auto}.footer-transparent{background-color:transparent;border-top:0}body:not(.theme-dark):not([data-bs-theme=dark]) .hide-theme-light{display:none!important}body:not(.theme-dark):not([data-bs-theme=dark]) .img-dark{display:none!important}body.theme-dark .hide-theme-dark,body[data-bs-theme=dark] .hide-theme-dark,body.theme-dark .img-light,body[data-bs-theme=dark] .img-light{display:none!important}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-body-color: #dce1e7;--tblr-body-color-rgb: 220, 225, 231;--tblr-muted: #49566c;--tblr-body-bg: #151f2c;--tblr-body-bg-rgb: 21, 31, 44;--tblr-emphasis-color: #ffffff;--tblr-emphasis-color-rgb: 255, 255, 255;--tblr-bg-forms: #151f2c;--tblr-bg-surface: #182433;--tblr-bg-surface-dark: #151f2c;--tblr-bg-surface-secondary: #1b293a;--tblr-bg-surface-tertiary: #151f2c;--tblr-link-color: #00aea3;--tblr-link-hover-color: #00857D;--tblr-active-bg: #1b293a;--tblr-disabled-color: var(--tblr-gray-700);--tblr-border-color: var(--tblr-dark-mode-border-color);--tblr-border-color-translucent: var( --tblr-dark-mode-border-color-translucent );--tblr-border-dark-color: var(--tblr-dark-mode-border-dark-color);--tblr-border-active-color: var( --tblr-dark-mode-border-active-color );--tblr-btn-color: #151f2c;--tblr-code-color: var(--tblr-body-color);--tblr-code-bg: #1f2e41;--tblr-primary-lt: #162e3a;--tblr-primary-lt-rgb: 22, 46, 58;--tblr-secondary-lt: #202d3c;--tblr-secondary-lt-rgb: 32, 45, 60;--tblr-success-lt: #1a3235;--tblr-success-lt-rgb: 26, 50, 53;--tblr-info-lt: #1c3044;--tblr-info-lt-rgb: 28, 48, 68;--tblr-warning-lt: #2e2b2f;--tblr-warning-lt-rgb: 46, 43, 47;--tblr-danger-lt: #2b2634;--tblr-danger-lt-rgb: 43, 38, 52;--tblr-light-lt: #2e3947;--tblr-light-lt-rgb: 46, 57, 71;--tblr-dark-lt: #182433;--tblr-dark-lt-rgb: 24, 36, 51;--tblr-muted-lt: #202d3c;--tblr-muted-lt-rgb: 32, 45, 60;--tblr-blue-lt: #162c43;--tblr-blue-lt-rgb: 22, 44, 67;--tblr-azure-lt: #1c3044;--tblr-azure-lt-rgb: 28, 48, 68;--tblr-indigo-lt: #1c2a45;--tblr-indigo-lt-rgb: 28, 42, 69;--tblr-purple-lt: #272742;--tblr-purple-lt-rgb: 39, 39, 66;--tblr-pink-lt: #2b2639;--tblr-pink-lt-rgb: 43, 38, 57;--tblr-red-lt: #2b2634;--tblr-red-lt-rgb: 43, 38, 52;--tblr-orange-lt: #2e2b2f;--tblr-orange-lt-rgb: 46, 43, 47;--tblr-yellow-lt: #2e302e;--tblr-yellow-lt-rgb: 46, 48, 46;--tblr-lime-lt: #213330;--tblr-lime-lt-rgb: 33, 51, 48;--tblr-green-lt: #1a3235;--tblr-green-lt-rgb: 26, 50, 53;--tblr-teal-lt: #17313a;--tblr-teal-lt-rgb: 23, 49, 58;--tblr-cyan-lt: #183140;--tblr-cyan-lt-rgb: 24, 49, 64;--tblr-x-lt: #16202e;--tblr-x-lt-rgb: 22, 32, 46;--tblr-facebook-lt: #182c46;--tblr-facebook-lt-rgb: 24, 44, 70;--tblr-twitter-lt: #193146;--tblr-twitter-lt-rgb: 25, 49, 70;--tblr-linkedin-lt: #172b41;--tblr-linkedin-lt-rgb: 23, 43, 65;--tblr-google-lt: #2c2834;--tblr-google-lt-rgb: 44, 40, 52;--tblr-youtube-lt: #2f202e;--tblr-youtube-lt-rgb: 47, 32, 46;--tblr-vimeo-lt: #183345;--tblr-vimeo-lt-rgb: 24, 51, 69;--tblr-dribbble-lt: #2d283c;--tblr-dribbble-lt-rgb: 45, 40, 60;--tblr-github-lt: #182330;--tblr-github-lt-rgb: 24, 35, 48;--tblr-instagram-lt: #2c2737;--tblr-instagram-lt-rgb: 44, 39, 55;--tblr-pinterest-lt: #292131;--tblr-pinterest-lt-rgb: 41, 33, 49;--tblr-vk-lt: #202e3f;--tblr-vk-lt-rgb: 32, 46, 63;--tblr-rss-lt: #2f312e;--tblr-rss-lt-rgb: 47, 49, 46;--tblr-flickr-lt: #162a44;--tblr-flickr-lt-rgb: 22, 42, 68;--tblr-bitbucket-lt: #162942;--tblr-bitbucket-lt-rgb: 22, 41, 66;--tblr-tabler-lt: #162c43;--tblr-tabler-lt-rgb: 22, 44, 67}[data-bs-theme=dark] .navbar-brand-autodark .navbar-brand-image{filter:brightness(0) invert(1)}.accordion{--tblr-accordion-color: var(--tblr-body-color)}.accordion-button:focus:not(:focus-visible){outline:none;box-shadow:none}.accordion-button:after{opacity:.7}.accordion-button:not(.collapsed){font-weight:var(--tblr-font-weight-bold);border-bottom-color:transparent;box-shadow:none}.accordion-button:not(.collapsed):after{opacity:1}.alert{--tblr-alert-color: var(--tblr-secondary);--tblr-alert-bg: var(--tblr-bg-surface);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-left:.25rem var(--tblr-border-style) var(--tblr-alert-color);box-shadow:#1824330a 0 2px 4px}.alert>:last-child{margin-bottom:0}.alert-important{border-color:transparent;background:var(--tblr-alert-color);color:#fff}.alert-important .alert-icon,.alert-important .alert-link,.alert-important .alert-title,.alert-important .alert-link:hover{color:inherit}.alert-important .btn-close{filter:var(--tblr-btn-close-white-filter)}.alert-link,.alert-link:hover{color:var(--tblr-alert-color)}.alert-primary{--tblr-alert-color: var(--tblr-primary)}.alert-secondary{--tblr-alert-color: var(--tblr-secondary)}.alert-success{--tblr-alert-color: var(--tblr-success)}.alert-info{--tblr-alert-color: var(--tblr-info)}.alert-warning{--tblr-alert-color: var(--tblr-warning)}.alert-danger{--tblr-alert-color: var(--tblr-danger)}.alert-light{--tblr-alert-color: var(--tblr-light)}.alert-dark{--tblr-alert-color: var(--tblr-dark)}.alert-muted{--tblr-alert-color: var(--tblr-muted)}.alert-blue{--tblr-alert-color: var(--tblr-blue)}.alert-azure{--tblr-alert-color: var(--tblr-azure)}.alert-indigo{--tblr-alert-color: var(--tblr-indigo)}.alert-purple{--tblr-alert-color: var(--tblr-purple)}.alert-pink{--tblr-alert-color: var(--tblr-pink)}.alert-red{--tblr-alert-color: var(--tblr-red)}.alert-orange{--tblr-alert-color: var(--tblr-orange)}.alert-yellow{--tblr-alert-color: var(--tblr-yellow)}.alert-lime{--tblr-alert-color: var(--tblr-lime)}.alert-green{--tblr-alert-color: var(--tblr-green)}.alert-teal{--tblr-alert-color: var(--tblr-teal)}.alert-cyan{--tblr-alert-color: var(--tblr-cyan)}.alert-x{--tblr-alert-color: var(--tblr-x)}.alert-facebook{--tblr-alert-color: var(--tblr-facebook)}.alert-twitter{--tblr-alert-color: var(--tblr-twitter)}.alert-linkedin{--tblr-alert-color: var(--tblr-linkedin)}.alert-google{--tblr-alert-color: var(--tblr-google)}.alert-youtube{--tblr-alert-color: var(--tblr-youtube)}.alert-vimeo{--tblr-alert-color: var(--tblr-vimeo)}.alert-dribbble{--tblr-alert-color: var(--tblr-dribbble)}.alert-github{--tblr-alert-color: var(--tblr-github)}.alert-instagram{--tblr-alert-color: var(--tblr-instagram)}.alert-pinterest{--tblr-alert-color: var(--tblr-pinterest)}.alert-vk{--tblr-alert-color: var(--tblr-vk)}.alert-rss{--tblr-alert-color: var(--tblr-rss)}.alert-flickr{--tblr-alert-color: var(--tblr-flickr)}.alert-bitbucket{--tblr-alert-color: var(--tblr-bitbucket)}.alert-tabler{--tblr-alert-color: var(--tblr-tabler)}.alert-icon{color:var(--tblr-alert-color);width:1.5rem!important;height:1.5rem!important;margin:-.125rem 1rem -.125rem 0}.alert-title{font-size:.875rem;line-height:1.25rem;font-weight:var(--tblr-font-weight-bold);margin-bottom:.25rem;color:var(--tblr-alert-color)}.avatar{--tblr-avatar-size: 2.5rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-bg: var(--tblr-bg-surface-secondary);--tblr-avatar-box-shadow: var(--tblr-box-shadow-border);--tblr-avatar-font-size: 1rem;--tblr-avatar-icon-size: 1.5rem;position:relative;width:var(--tblr-avatar-size);height:var(--tblr-avatar-size);font-size:var(--tblr-avatar-font-size);font-weight:var(--tblr-font-weight-medium);line-height:1;display:inline-flex;align-items:center;justify-content:center;color:var(--tblr-secondary);text-align:center;text-transform:uppercase;vertical-align:bottom;user-select:none;background:var(--tblr-avatar-bg) no-repeat center/cover;border-radius:var(--tblr-border-radius);box-shadow:var(--tblr-avatar-box-shadow)}.avatar .icon{width:var(--tblr-avatar-icon-size);height:var(--tblr-avatar-icon-size)}.avatar .badge{position:absolute;right:0;bottom:0;border-radius:100rem;box-shadow:0 0 0 calc(var(--tblr-avatar-status-size) / 4) var(--tblr-bg-surface)}a.avatar{cursor:pointer}.avatar-rounded{border-radius:100rem}.avatar-xxs{--tblr-avatar-size: 1rem;--tblr-avatar-status-size: .25rem;--tblr-avatar-font-size: .5rem;--tblr-avatar-icon-size: .75rem}.avatar-xxs .badge:empty{width:.25rem;height:.25rem}.avatar-xs{--tblr-avatar-size: 1.25rem;--tblr-avatar-status-size: .375rem;--tblr-avatar-font-size: .625rem;--tblr-avatar-icon-size: .75rem}.avatar-xs .badge:empty{width:.375rem;height:.375rem}.avatar-sm{--tblr-avatar-size: 2rem;--tblr-avatar-status-size: .5rem;--tblr-avatar-font-size: .75rem;--tblr-avatar-icon-size: 1.5rem}.avatar-sm .badge:empty{width:.5rem;height:.5rem}.avatar-md{--tblr-avatar-size: 2.5rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-font-size: .875rem;--tblr-avatar-icon-size: 1.5rem}.avatar-md .badge:empty{width:.75rem;height:.75rem}.avatar-lg{--tblr-avatar-size: 3rem;--tblr-avatar-status-size: .75rem;--tblr-avatar-font-size: 1.25rem;--tblr-avatar-icon-size: 2rem}.avatar-lg .badge:empty{width:.75rem;height:.75rem}.avatar-xl{--tblr-avatar-size: 5rem;--tblr-avatar-status-size: 1rem;--tblr-avatar-font-size: 2rem;--tblr-avatar-icon-size: 3rem}.avatar-xl .badge:empty{width:1rem;height:1rem}.avatar-2xl{--tblr-avatar-size: 7rem;--tblr-avatar-status-size: 1rem;--tblr-avatar-font-size: 3rem;--tblr-avatar-icon-size: 5rem}.avatar-2xl .badge:empty{width:1rem;height:1rem}.avatar-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.avatar-list a.avatar:hover{z-index:1}.avatar-list-stacked{display:block;--tblr-list-gap: 0}.avatar-list-stacked .avatar{margin-right:calc(-.5 * var(--tblr-avatar-size))!important;box-shadow:var(--tblr-avatar-box-shadow),0 0 0 2px var(--tblr-card-cap-bg, var(--tblr-card-bg, var(--tblr-bg-surface)))}.avatar-upload{width:4rem;height:4rem;border:var(--tblr-border-width) dashed var(--tblr-border-color);background:var(--tblr-bg-forms);flex-direction:column;transition:color .3s,background-color .3s}@media (prefers-reduced-motion: reduce){.avatar-upload{transition:none}}.avatar-upload svg{width:1.5rem;height:1.5rem;stroke-width:1}.avatar-upload:hover{border-color:var(--tblr-primary);color:var(--tblr-primary);text-decoration:none}.avatar-upload-text{font-size:.625rem;line-height:1;margin-top:.25rem}.avatar-cover{margin-top:calc(-.5 * var(--tblr-avatar-size));box-shadow:0 0 0 .25rem var(--tblr-card-bg, var(--tblr-body-bg))}.badge{justify-content:center;align-items:center;background:var(--tblr-bg-surface-secondary);overflow:hidden;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) transparent;min-width:1.35714285em;font-weight:var(--tblr-font-weight-bold);letter-spacing:.04em;vertical-align:bottom}a.badge{color:var(--tblr-bg-surface)}.badge .avatar{box-sizing:content-box;width:1.25rem;height:1.25rem;margin:0 .5rem 0 -.5rem}.badge .icon{width:1em;height:1em;font-size:1rem;stroke-width:2}.badge:empty,.badge-empty{display:inline-block;width:.5rem;height:.5rem;min-width:0;min-height:auto;padding:0;border-radius:100rem;vertical-align:baseline}.badge-outline{background-color:transparent;border:var(--tblr-border-width) var(--tblr-border-style) currentColor}.badge-pill{border-radius:100rem}.badges-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.badge-notification{position:absolute!important;top:0!important;right:0!important;transform:translate(50%,-50%);z-index:1}.badge-blink{animation:blink 2s infinite}.breadcrumb{--tblr-breadcrumb-item-active-font-weight: var(--tblr-font-weight-bold);--tblr-breadcrumb-item-disabled-color: var(--tblr-disabled-color);--tblr-breadcrumb-link-color: var(--tblr-link-color);padding:0;margin:0;background:transparent}.breadcrumb a{color:var(--tblr-breadcrumb-link-color)}.breadcrumb a:hover{text-decoration:underline}.breadcrumb-muted{--tblr-breadcrumb-link-color: var(--tblr-secondary)}.breadcrumb-item.active{font-weight:var(--tblr-breadcrumb-item-active-font-weight)}.breadcrumb-item.active a{color:inherit;pointer-events:none}.breadcrumb-item.disabled{color:var(--tblr-breadcrumb-item-disabled-color)}.breadcrumb-item.disabled:before{color:inherit}.breadcrumb-item.disabled a{color:inherit;pointer-events:none}.breadcrumb-dots{--tblr-breadcrumb-divider: "\b7"}.breadcrumb-arrows{--tblr-breadcrumb-divider: "\203a"}.breadcrumb-bullets{--tblr-breadcrumb-divider: "\2022"}.btn{--tblr-btn-icon-size: 1.25rem;--tblr-btn-bg: var(--tblr-bg-surface);--tblr-btn-color: var(--tblr-body-color);--tblr-btn-border-color: var(--tblr-border-color);--tblr-btn-hover-bg: var(--tblr-btn-bg);--tblr-btn-hover-border-color: var(--tblr-border-active-color);--tblr-btn-box-shadow: var(--tblr-box-shadow-input);--tblr-btn-active-color: var(--tblr-primary);--tblr-btn-active-bg: rgba(var(--tblr-primary-rgb), .04);--tblr-btn-active-border-color: var(--tblr-primary);display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;box-shadow:var(--tblr-btn-box-shadow)}.btn .icon{width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);min-width:var(--tblr-btn-icon-size);font-size:var(--tblr-btn-icon-size);margin:0 calc(var(--tblr-btn-padding-x) / 2) 0 calc(var(--tblr-btn-padding-x) / -4);vertical-align:bottom;color:inherit}.btn .avatar{width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);margin:0 calc(var(--tblr-btn-padding-x) / 2) 0 calc(var(--tblr-btn-padding-x) / -4)}.btn .icon-right{margin:0 calc(var(--tblr-btn-padding-x) / -4) 0 calc(var(--tblr-btn-padding-x) / 2)}.btn .badge{top:auto}.btn-check+.btn:hover{color:var(--tblr-btn-hover-color);background-color:var(--tblr-btn-hover-bg);border-color:var(--tblr-btn-hover-border-color)}.btn-link{color:#009f95;background-color:transparent;border-color:transparent;box-shadow:none}.btn-link .icon{color:inherit}.btn-link:hover{color:#006a64;border-color:transparent}.btn-primary{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-primary-fg);--tblr-btn-bg: var(--tblr-primary);--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-bg: var(--tblr-primary-darken);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: var(--tblr-primary-darken);--tblr-btn-disabled-bg: var(--tblr-primary);--tblr-btn-disabled-color: var(--tblr-primary-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-primary{--tblr-btn-color: var(--tblr-primary);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-primary);--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-primary);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: var(--tblr-primary);--tblr-btn-disabled-color: var(--tblr-primary);--tblr-btn-disabled-border-color: var(--tblr-primary)}.btn-secondary{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-secondary-fg);--tblr-btn-bg: var(--tblr-secondary);--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-bg: var(--tblr-secondary-darken);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: var(--tblr-secondary-darken);--tblr-btn-disabled-bg: var(--tblr-secondary);--tblr-btn-disabled-color: var(--tblr-secondary-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-secondary{--tblr-btn-color: var(--tblr-secondary);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-secondary);--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-secondary);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: var(--tblr-secondary);--tblr-btn-disabled-color: var(--tblr-secondary);--tblr-btn-disabled-border-color: var(--tblr-secondary)}.btn-success{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-success-fg);--tblr-btn-bg: var(--tblr-success);--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-bg: var(--tblr-success-darken);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: var(--tblr-success-darken);--tblr-btn-disabled-bg: var(--tblr-success);--tblr-btn-disabled-color: var(--tblr-success-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-success{--tblr-btn-color: var(--tblr-success);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-success);--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-success);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: var(--tblr-success);--tblr-btn-disabled-color: var(--tblr-success);--tblr-btn-disabled-border-color: var(--tblr-success)}.btn-info{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-info-fg);--tblr-btn-bg: var(--tblr-info);--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-bg: var(--tblr-info-darken);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: var(--tblr-info-darken);--tblr-btn-disabled-bg: var(--tblr-info);--tblr-btn-disabled-color: var(--tblr-info-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-info{--tblr-btn-color: var(--tblr-info);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-info);--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-info);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: var(--tblr-info);--tblr-btn-disabled-color: var(--tblr-info);--tblr-btn-disabled-border-color: var(--tblr-info)}.btn-warning{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-warning-fg);--tblr-btn-bg: var(--tblr-warning);--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-bg: var(--tblr-warning-darken);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: var(--tblr-warning-darken);--tblr-btn-disabled-bg: var(--tblr-warning);--tblr-btn-disabled-color: var(--tblr-warning-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-warning{--tblr-btn-color: var(--tblr-warning);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-warning);--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-warning);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: var(--tblr-warning);--tblr-btn-disabled-color: var(--tblr-warning);--tblr-btn-disabled-border-color: var(--tblr-warning)}.btn-danger{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-danger-fg);--tblr-btn-bg: var(--tblr-danger);--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-bg: var(--tblr-danger-darken);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: var(--tblr-danger-darken);--tblr-btn-disabled-bg: var(--tblr-danger);--tblr-btn-disabled-color: var(--tblr-danger-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-danger{--tblr-btn-color: var(--tblr-danger);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-danger);--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-danger);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: var(--tblr-danger);--tblr-btn-disabled-color: var(--tblr-danger);--tblr-btn-disabled-border-color: var(--tblr-danger)}.btn-light{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-light-fg);--tblr-btn-bg: var(--tblr-light);--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-bg: var(--tblr-light-darken);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: var(--tblr-light-darken);--tblr-btn-disabled-bg: var(--tblr-light);--tblr-btn-disabled-color: var(--tblr-light-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-light{--tblr-btn-color: var(--tblr-light);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-light);--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-light);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: var(--tblr-light);--tblr-btn-disabled-color: var(--tblr-light);--tblr-btn-disabled-border-color: var(--tblr-light)}.btn-dark{--tblr-btn-border-color: var(--tblr-dark-mode-border-color);--tblr-btn-hover-border-color: var(--tblr-dark-mode-border-active-color);--tblr-btn-active-border-color: var(--tblr-dark-mode-border-active-color);--tblr-btn-color: var(--tblr-dark-fg);--tblr-btn-bg: var(--tblr-dark);--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-bg: var(--tblr-dark-darken);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: var(--tblr-dark-darken);--tblr-btn-disabled-bg: var(--tblr-dark);--tblr-btn-disabled-color: var(--tblr-dark-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-dark{--tblr-btn-color: var(--tblr-dark);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-dark);--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-dark);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: var(--tblr-dark);--tblr-btn-disabled-color: var(--tblr-dark);--tblr-btn-disabled-border-color: var(--tblr-dark)}.btn-muted{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-muted-fg);--tblr-btn-bg: var(--tblr-muted);--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-bg: var(--tblr-muted-darken);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: var(--tblr-muted-darken);--tblr-btn-disabled-bg: var(--tblr-muted);--tblr-btn-disabled-color: var(--tblr-muted-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-muted{--tblr-btn-color: var(--tblr-muted);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-muted);--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-muted);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: var(--tblr-muted);--tblr-btn-disabled-color: var(--tblr-muted);--tblr-btn-disabled-border-color: var(--tblr-muted)}.btn-blue{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-blue-fg);--tblr-btn-bg: var(--tblr-blue);--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-bg: var(--tblr-blue-darken);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: var(--tblr-blue-darken);--tblr-btn-disabled-bg: var(--tblr-blue);--tblr-btn-disabled-color: var(--tblr-blue-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-blue{--tblr-btn-color: var(--tblr-blue);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-blue);--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-blue);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: var(--tblr-blue);--tblr-btn-disabled-color: var(--tblr-blue);--tblr-btn-disabled-border-color: var(--tblr-blue)}.btn-azure{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-azure-fg);--tblr-btn-bg: var(--tblr-azure);--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-bg: var(--tblr-azure-darken);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: var(--tblr-azure-darken);--tblr-btn-disabled-bg: var(--tblr-azure);--tblr-btn-disabled-color: var(--tblr-azure-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-azure{--tblr-btn-color: var(--tblr-azure);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-azure);--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-azure);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: var(--tblr-azure);--tblr-btn-disabled-color: var(--tblr-azure);--tblr-btn-disabled-border-color: var(--tblr-azure)}.btn-indigo{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-indigo-fg);--tblr-btn-bg: var(--tblr-indigo);--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-bg: var(--tblr-indigo-darken);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: var(--tblr-indigo-darken);--tblr-btn-disabled-bg: var(--tblr-indigo);--tblr-btn-disabled-color: var(--tblr-indigo-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-indigo{--tblr-btn-color: var(--tblr-indigo);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-indigo);--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-indigo);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: var(--tblr-indigo);--tblr-btn-disabled-color: var(--tblr-indigo);--tblr-btn-disabled-border-color: var(--tblr-indigo)}.btn-purple{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-purple-fg);--tblr-btn-bg: var(--tblr-purple);--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-bg: var(--tblr-purple-darken);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: var(--tblr-purple-darken);--tblr-btn-disabled-bg: var(--tblr-purple);--tblr-btn-disabled-color: var(--tblr-purple-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-purple{--tblr-btn-color: var(--tblr-purple);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-purple);--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-purple);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: var(--tblr-purple);--tblr-btn-disabled-color: var(--tblr-purple);--tblr-btn-disabled-border-color: var(--tblr-purple)}.btn-pink{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-pink-fg);--tblr-btn-bg: var(--tblr-pink);--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-bg: var(--tblr-pink-darken);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: var(--tblr-pink-darken);--tblr-btn-disabled-bg: var(--tblr-pink);--tblr-btn-disabled-color: var(--tblr-pink-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-pink{--tblr-btn-color: var(--tblr-pink);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-pink);--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-pink);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: var(--tblr-pink);--tblr-btn-disabled-color: var(--tblr-pink);--tblr-btn-disabled-border-color: var(--tblr-pink)}.btn-red{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-red-fg);--tblr-btn-bg: var(--tblr-red);--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-bg: var(--tblr-red-darken);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: var(--tblr-red-darken);--tblr-btn-disabled-bg: var(--tblr-red);--tblr-btn-disabled-color: var(--tblr-red-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-red{--tblr-btn-color: var(--tblr-red);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-red);--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-red);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: var(--tblr-red);--tblr-btn-disabled-color: var(--tblr-red);--tblr-btn-disabled-border-color: var(--tblr-red)}.btn-orange{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-orange-fg);--tblr-btn-bg: var(--tblr-orange);--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-bg: var(--tblr-orange-darken);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: var(--tblr-orange-darken);--tblr-btn-disabled-bg: var(--tblr-orange);--tblr-btn-disabled-color: var(--tblr-orange-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-orange{--tblr-btn-color: var(--tblr-orange);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-orange);--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-orange);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: var(--tblr-orange);--tblr-btn-disabled-color: var(--tblr-orange);--tblr-btn-disabled-border-color: var(--tblr-orange)}.btn-yellow{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-yellow-fg);--tblr-btn-bg: var(--tblr-yellow);--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-bg: var(--tblr-yellow-darken);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: var(--tblr-yellow-darken);--tblr-btn-disabled-bg: var(--tblr-yellow);--tblr-btn-disabled-color: var(--tblr-yellow-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-yellow{--tblr-btn-color: var(--tblr-yellow);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-yellow);--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-yellow);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: var(--tblr-yellow);--tblr-btn-disabled-color: var(--tblr-yellow);--tblr-btn-disabled-border-color: var(--tblr-yellow)}.btn-lime{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-lime-fg);--tblr-btn-bg: var(--tblr-lime);--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-bg: var(--tblr-lime-darken);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: var(--tblr-lime-darken);--tblr-btn-disabled-bg: var(--tblr-lime);--tblr-btn-disabled-color: var(--tblr-lime-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-lime{--tblr-btn-color: var(--tblr-lime);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-lime);--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-lime);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: var(--tblr-lime);--tblr-btn-disabled-color: var(--tblr-lime);--tblr-btn-disabled-border-color: var(--tblr-lime)}.btn-green{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-green-fg);--tblr-btn-bg: var(--tblr-green);--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-bg: var(--tblr-green-darken);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: var(--tblr-green-darken);--tblr-btn-disabled-bg: var(--tblr-green);--tblr-btn-disabled-color: var(--tblr-green-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-green{--tblr-btn-color: var(--tblr-green);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-green);--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-green);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: var(--tblr-green);--tblr-btn-disabled-color: var(--tblr-green);--tblr-btn-disabled-border-color: var(--tblr-green)}.btn-teal{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-teal-fg);--tblr-btn-bg: var(--tblr-teal);--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-bg: var(--tblr-teal-darken);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: var(--tblr-teal-darken);--tblr-btn-disabled-bg: var(--tblr-teal);--tblr-btn-disabled-color: var(--tblr-teal-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-teal{--tblr-btn-color: var(--tblr-teal);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-teal);--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-teal);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: var(--tblr-teal);--tblr-btn-disabled-color: var(--tblr-teal);--tblr-btn-disabled-border-color: var(--tblr-teal)}.btn-cyan{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-cyan-fg);--tblr-btn-bg: var(--tblr-cyan);--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-bg: var(--tblr-cyan-darken);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: var(--tblr-cyan-darken);--tblr-btn-disabled-bg: var(--tblr-cyan);--tblr-btn-disabled-color: var(--tblr-cyan-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-cyan{--tblr-btn-color: var(--tblr-cyan);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-cyan);--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-cyan);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: var(--tblr-cyan);--tblr-btn-disabled-color: var(--tblr-cyan);--tblr-btn-disabled-border-color: var(--tblr-cyan)}.btn-x{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-x-fg);--tblr-btn-bg: var(--tblr-x);--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-bg: var(--tblr-x-darken);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: var(--tblr-x-darken);--tblr-btn-disabled-bg: var(--tblr-x);--tblr-btn-disabled-color: var(--tblr-x-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-x{--tblr-btn-color: var(--tblr-x);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-x);--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-x);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: var(--tblr-x);--tblr-btn-disabled-color: var(--tblr-x);--tblr-btn-disabled-border-color: var(--tblr-x)}.btn-facebook{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-facebook-fg);--tblr-btn-bg: var(--tblr-facebook);--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-bg: var(--tblr-facebook-darken);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: var(--tblr-facebook-darken);--tblr-btn-disabled-bg: var(--tblr-facebook);--tblr-btn-disabled-color: var(--tblr-facebook-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-facebook{--tblr-btn-color: var(--tblr-facebook);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-facebook);--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-facebook);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: var(--tblr-facebook);--tblr-btn-disabled-color: var(--tblr-facebook);--tblr-btn-disabled-border-color: var(--tblr-facebook)}.btn-twitter{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-twitter-fg);--tblr-btn-bg: var(--tblr-twitter);--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-bg: var(--tblr-twitter-darken);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: var(--tblr-twitter-darken);--tblr-btn-disabled-bg: var(--tblr-twitter);--tblr-btn-disabled-color: var(--tblr-twitter-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-twitter{--tblr-btn-color: var(--tblr-twitter);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-twitter);--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-twitter);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: var(--tblr-twitter);--tblr-btn-disabled-color: var(--tblr-twitter);--tblr-btn-disabled-border-color: var(--tblr-twitter)}.btn-linkedin{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-linkedin-fg);--tblr-btn-bg: var(--tblr-linkedin);--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-bg: var(--tblr-linkedin-darken);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: var(--tblr-linkedin-darken);--tblr-btn-disabled-bg: var(--tblr-linkedin);--tblr-btn-disabled-color: var(--tblr-linkedin-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-linkedin{--tblr-btn-color: var(--tblr-linkedin);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-linkedin);--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-linkedin);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: var(--tblr-linkedin);--tblr-btn-disabled-color: var(--tblr-linkedin);--tblr-btn-disabled-border-color: var(--tblr-linkedin)}.btn-google{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-google-fg);--tblr-btn-bg: var(--tblr-google);--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-bg: var(--tblr-google-darken);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: var(--tblr-google-darken);--tblr-btn-disabled-bg: var(--tblr-google);--tblr-btn-disabled-color: var(--tblr-google-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-google{--tblr-btn-color: var(--tblr-google);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-google);--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-google);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: var(--tblr-google);--tblr-btn-disabled-color: var(--tblr-google);--tblr-btn-disabled-border-color: var(--tblr-google)}.btn-youtube{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-youtube-fg);--tblr-btn-bg: var(--tblr-youtube);--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-bg: var(--tblr-youtube-darken);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: var(--tblr-youtube-darken);--tblr-btn-disabled-bg: var(--tblr-youtube);--tblr-btn-disabled-color: var(--tblr-youtube-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-youtube{--tblr-btn-color: var(--tblr-youtube);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-youtube);--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-youtube);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: var(--tblr-youtube);--tblr-btn-disabled-color: var(--tblr-youtube);--tblr-btn-disabled-border-color: var(--tblr-youtube)}.btn-vimeo{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-vimeo-fg);--tblr-btn-bg: var(--tblr-vimeo);--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-bg: var(--tblr-vimeo-darken);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: var(--tblr-vimeo-darken);--tblr-btn-disabled-bg: var(--tblr-vimeo);--tblr-btn-disabled-color: var(--tblr-vimeo-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-vimeo{--tblr-btn-color: var(--tblr-vimeo);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-vimeo);--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-vimeo);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: var(--tblr-vimeo);--tblr-btn-disabled-color: var(--tblr-vimeo);--tblr-btn-disabled-border-color: var(--tblr-vimeo)}.btn-dribbble{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-dribbble-fg);--tblr-btn-bg: var(--tblr-dribbble);--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-bg: var(--tblr-dribbble-darken);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: var(--tblr-dribbble-darken);--tblr-btn-disabled-bg: var(--tblr-dribbble);--tblr-btn-disabled-color: var(--tblr-dribbble-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-dribbble{--tblr-btn-color: var(--tblr-dribbble);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-dribbble);--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-dribbble);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: var(--tblr-dribbble);--tblr-btn-disabled-color: var(--tblr-dribbble);--tblr-btn-disabled-border-color: var(--tblr-dribbble)}.btn-github{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-github-fg);--tblr-btn-bg: var(--tblr-github);--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-bg: var(--tblr-github-darken);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: var(--tblr-github-darken);--tblr-btn-disabled-bg: var(--tblr-github);--tblr-btn-disabled-color: var(--tblr-github-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-github{--tblr-btn-color: var(--tblr-github);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-github);--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-github);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: var(--tblr-github);--tblr-btn-disabled-color: var(--tblr-github);--tblr-btn-disabled-border-color: var(--tblr-github)}.btn-instagram{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-instagram-fg);--tblr-btn-bg: var(--tblr-instagram);--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-bg: var(--tblr-instagram-darken);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: var(--tblr-instagram-darken);--tblr-btn-disabled-bg: var(--tblr-instagram);--tblr-btn-disabled-color: var(--tblr-instagram-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-instagram{--tblr-btn-color: var(--tblr-instagram);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-instagram);--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-instagram);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: var(--tblr-instagram);--tblr-btn-disabled-color: var(--tblr-instagram);--tblr-btn-disabled-border-color: var(--tblr-instagram)}.btn-pinterest{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-pinterest-fg);--tblr-btn-bg: var(--tblr-pinterest);--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-bg: var(--tblr-pinterest-darken);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: var(--tblr-pinterest-darken);--tblr-btn-disabled-bg: var(--tblr-pinterest);--tblr-btn-disabled-color: var(--tblr-pinterest-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-pinterest{--tblr-btn-color: var(--tblr-pinterest);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-pinterest);--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-pinterest);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: var(--tblr-pinterest);--tblr-btn-disabled-color: var(--tblr-pinterest);--tblr-btn-disabled-border-color: var(--tblr-pinterest)}.btn-vk{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-vk-fg);--tblr-btn-bg: var(--tblr-vk);--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-bg: var(--tblr-vk-darken);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: var(--tblr-vk-darken);--tblr-btn-disabled-bg: var(--tblr-vk);--tblr-btn-disabled-color: var(--tblr-vk-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-vk{--tblr-btn-color: var(--tblr-vk);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-vk);--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-vk);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: var(--tblr-vk);--tblr-btn-disabled-color: var(--tblr-vk);--tblr-btn-disabled-border-color: var(--tblr-vk)}.btn-rss{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-rss-fg);--tblr-btn-bg: var(--tblr-rss);--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-bg: var(--tblr-rss-darken);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: var(--tblr-rss-darken);--tblr-btn-disabled-bg: var(--tblr-rss);--tblr-btn-disabled-color: var(--tblr-rss-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-rss{--tblr-btn-color: var(--tblr-rss);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-rss);--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-rss);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: var(--tblr-rss);--tblr-btn-disabled-color: var(--tblr-rss);--tblr-btn-disabled-border-color: var(--tblr-rss)}.btn-flickr{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-flickr-fg);--tblr-btn-bg: var(--tblr-flickr);--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-bg: var(--tblr-flickr-darken);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: var(--tblr-flickr-darken);--tblr-btn-disabled-bg: var(--tblr-flickr);--tblr-btn-disabled-color: var(--tblr-flickr-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-flickr{--tblr-btn-color: var(--tblr-flickr);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-flickr);--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-flickr);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: var(--tblr-flickr);--tblr-btn-disabled-color: var(--tblr-flickr);--tblr-btn-disabled-border-color: var(--tblr-flickr)}.btn-bitbucket{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-bitbucket-fg);--tblr-btn-bg: var(--tblr-bitbucket);--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-bg: var(--tblr-bitbucket-darken);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: var(--tblr-bitbucket-darken);--tblr-btn-disabled-bg: var(--tblr-bitbucket);--tblr-btn-disabled-color: var(--tblr-bitbucket-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-bitbucket{--tblr-btn-color: var(--tblr-bitbucket);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-bitbucket);--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-bitbucket);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: var(--tblr-bitbucket);--tblr-btn-disabled-color: var(--tblr-bitbucket);--tblr-btn-disabled-border-color: var(--tblr-bitbucket)}.btn-tabler{--tblr-btn-border-color: transparent;--tblr-btn-hover-border-color: transparent;--tblr-btn-active-border-color: transparent;--tblr-btn-color: var(--tblr-tabler-fg);--tblr-btn-bg: var(--tblr-tabler);--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-bg: var(--tblr-tabler-darken);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: var(--tblr-tabler-darken);--tblr-btn-disabled-bg: var(--tblr-tabler);--tblr-btn-disabled-color: var(--tblr-tabler-fg);--tblr-btn-box-shadow: var(--tblr-box-shadow-input)}.btn-outline-tabler{--tblr-btn-color: var(--tblr-tabler);--tblr-btn-bg: transparent;--tblr-btn-border-color: var(--tblr-tabler);--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-border-color: transparent;--tblr-btn-hover-bg: var(--tblr-tabler);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: var(--tblr-tabler);--tblr-btn-disabled-color: var(--tblr-tabler);--tblr-btn-disabled-border-color: var(--tblr-tabler)}.btn-ghost-primary{--tblr-btn-color: var(--tblr-primary);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-primary-fg);--tblr-btn-hover-bg: var(--tblr-primary);--tblr-btn-hover-border-color: var(--tblr-primary);--tblr-btn-active-color: var(--tblr-primary-fg);--tblr-btn-active-bg: var(--tblr-primary);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-primary);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-secondary{--tblr-btn-color: var(--tblr-secondary);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-secondary-fg);--tblr-btn-hover-bg: var(--tblr-secondary);--tblr-btn-hover-border-color: var(--tblr-secondary);--tblr-btn-active-color: var(--tblr-secondary-fg);--tblr-btn-active-bg: var(--tblr-secondary);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-secondary);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-success{--tblr-btn-color: var(--tblr-success);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-success-fg);--tblr-btn-hover-bg: var(--tblr-success);--tblr-btn-hover-border-color: var(--tblr-success);--tblr-btn-active-color: var(--tblr-success-fg);--tblr-btn-active-bg: var(--tblr-success);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-success);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-info{--tblr-btn-color: var(--tblr-info);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-info-fg);--tblr-btn-hover-bg: var(--tblr-info);--tblr-btn-hover-border-color: var(--tblr-info);--tblr-btn-active-color: var(--tblr-info-fg);--tblr-btn-active-bg: var(--tblr-info);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-info);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-warning{--tblr-btn-color: var(--tblr-warning);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-warning-fg);--tblr-btn-hover-bg: var(--tblr-warning);--tblr-btn-hover-border-color: var(--tblr-warning);--tblr-btn-active-color: var(--tblr-warning-fg);--tblr-btn-active-bg: var(--tblr-warning);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-warning);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-danger{--tblr-btn-color: var(--tblr-danger);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-danger-fg);--tblr-btn-hover-bg: var(--tblr-danger);--tblr-btn-hover-border-color: var(--tblr-danger);--tblr-btn-active-color: var(--tblr-danger-fg);--tblr-btn-active-bg: var(--tblr-danger);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-danger);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-light{--tblr-btn-color: var(--tblr-light);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-light-fg);--tblr-btn-hover-bg: var(--tblr-light);--tblr-btn-hover-border-color: var(--tblr-light);--tblr-btn-active-color: var(--tblr-light-fg);--tblr-btn-active-bg: var(--tblr-light);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-light);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-dark{--tblr-btn-color: var(--tblr-dark);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-dark-fg);--tblr-btn-hover-bg: var(--tblr-dark);--tblr-btn-hover-border-color: var(--tblr-dark);--tblr-btn-active-color: var(--tblr-dark-fg);--tblr-btn-active-bg: var(--tblr-dark);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-dark);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-muted{--tblr-btn-color: var(--tblr-muted);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-muted-fg);--tblr-btn-hover-bg: var(--tblr-muted);--tblr-btn-hover-border-color: var(--tblr-muted);--tblr-btn-active-color: var(--tblr-muted-fg);--tblr-btn-active-bg: var(--tblr-muted);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-muted);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-blue{--tblr-btn-color: var(--tblr-blue);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-blue-fg);--tblr-btn-hover-bg: var(--tblr-blue);--tblr-btn-hover-border-color: var(--tblr-blue);--tblr-btn-active-color: var(--tblr-blue-fg);--tblr-btn-active-bg: var(--tblr-blue);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-blue);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-azure{--tblr-btn-color: var(--tblr-azure);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-azure-fg);--tblr-btn-hover-bg: var(--tblr-azure);--tblr-btn-hover-border-color: var(--tblr-azure);--tblr-btn-active-color: var(--tblr-azure-fg);--tblr-btn-active-bg: var(--tblr-azure);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-azure);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-indigo{--tblr-btn-color: var(--tblr-indigo);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-indigo-fg);--tblr-btn-hover-bg: var(--tblr-indigo);--tblr-btn-hover-border-color: var(--tblr-indigo);--tblr-btn-active-color: var(--tblr-indigo-fg);--tblr-btn-active-bg: var(--tblr-indigo);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-indigo);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-purple{--tblr-btn-color: var(--tblr-purple);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-purple-fg);--tblr-btn-hover-bg: var(--tblr-purple);--tblr-btn-hover-border-color: var(--tblr-purple);--tblr-btn-active-color: var(--tblr-purple-fg);--tblr-btn-active-bg: var(--tblr-purple);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-purple);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-pink{--tblr-btn-color: var(--tblr-pink);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-pink-fg);--tblr-btn-hover-bg: var(--tblr-pink);--tblr-btn-hover-border-color: var(--tblr-pink);--tblr-btn-active-color: var(--tblr-pink-fg);--tblr-btn-active-bg: var(--tblr-pink);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-pink);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-red{--tblr-btn-color: var(--tblr-red);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-red-fg);--tblr-btn-hover-bg: var(--tblr-red);--tblr-btn-hover-border-color: var(--tblr-red);--tblr-btn-active-color: var(--tblr-red-fg);--tblr-btn-active-bg: var(--tblr-red);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-red);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-orange{--tblr-btn-color: var(--tblr-orange);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-orange-fg);--tblr-btn-hover-bg: var(--tblr-orange);--tblr-btn-hover-border-color: var(--tblr-orange);--tblr-btn-active-color: var(--tblr-orange-fg);--tblr-btn-active-bg: var(--tblr-orange);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-orange);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-yellow{--tblr-btn-color: var(--tblr-yellow);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-yellow-fg);--tblr-btn-hover-bg: var(--tblr-yellow);--tblr-btn-hover-border-color: var(--tblr-yellow);--tblr-btn-active-color: var(--tblr-yellow-fg);--tblr-btn-active-bg: var(--tblr-yellow);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-yellow);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-lime{--tblr-btn-color: var(--tblr-lime);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-lime-fg);--tblr-btn-hover-bg: var(--tblr-lime);--tblr-btn-hover-border-color: var(--tblr-lime);--tblr-btn-active-color: var(--tblr-lime-fg);--tblr-btn-active-bg: var(--tblr-lime);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-lime);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-green{--tblr-btn-color: var(--tblr-green);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-green-fg);--tblr-btn-hover-bg: var(--tblr-green);--tblr-btn-hover-border-color: var(--tblr-green);--tblr-btn-active-color: var(--tblr-green-fg);--tblr-btn-active-bg: var(--tblr-green);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-green);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-teal{--tblr-btn-color: var(--tblr-teal);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-teal-fg);--tblr-btn-hover-bg: var(--tblr-teal);--tblr-btn-hover-border-color: var(--tblr-teal);--tblr-btn-active-color: var(--tblr-teal-fg);--tblr-btn-active-bg: var(--tblr-teal);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-teal);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-cyan{--tblr-btn-color: var(--tblr-cyan);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-cyan-fg);--tblr-btn-hover-bg: var(--tblr-cyan);--tblr-btn-hover-border-color: var(--tblr-cyan);--tblr-btn-active-color: var(--tblr-cyan-fg);--tblr-btn-active-bg: var(--tblr-cyan);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-cyan);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-x{--tblr-btn-color: var(--tblr-x);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-x-fg);--tblr-btn-hover-bg: var(--tblr-x);--tblr-btn-hover-border-color: var(--tblr-x);--tblr-btn-active-color: var(--tblr-x-fg);--tblr-btn-active-bg: var(--tblr-x);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-x);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-facebook{--tblr-btn-color: var(--tblr-facebook);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-facebook-fg);--tblr-btn-hover-bg: var(--tblr-facebook);--tblr-btn-hover-border-color: var(--tblr-facebook);--tblr-btn-active-color: var(--tblr-facebook-fg);--tblr-btn-active-bg: var(--tblr-facebook);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-facebook);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-twitter{--tblr-btn-color: var(--tblr-twitter);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-twitter-fg);--tblr-btn-hover-bg: var(--tblr-twitter);--tblr-btn-hover-border-color: var(--tblr-twitter);--tblr-btn-active-color: var(--tblr-twitter-fg);--tblr-btn-active-bg: var(--tblr-twitter);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-twitter);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-linkedin{--tblr-btn-color: var(--tblr-linkedin);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-linkedin-fg);--tblr-btn-hover-bg: var(--tblr-linkedin);--tblr-btn-hover-border-color: var(--tblr-linkedin);--tblr-btn-active-color: var(--tblr-linkedin-fg);--tblr-btn-active-bg: var(--tblr-linkedin);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-linkedin);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-google{--tblr-btn-color: var(--tblr-google);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-google-fg);--tblr-btn-hover-bg: var(--tblr-google);--tblr-btn-hover-border-color: var(--tblr-google);--tblr-btn-active-color: var(--tblr-google-fg);--tblr-btn-active-bg: var(--tblr-google);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-google);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-youtube{--tblr-btn-color: var(--tblr-youtube);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-youtube-fg);--tblr-btn-hover-bg: var(--tblr-youtube);--tblr-btn-hover-border-color: var(--tblr-youtube);--tblr-btn-active-color: var(--tblr-youtube-fg);--tblr-btn-active-bg: var(--tblr-youtube);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-youtube);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-vimeo{--tblr-btn-color: var(--tblr-vimeo);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-vimeo-fg);--tblr-btn-hover-bg: var(--tblr-vimeo);--tblr-btn-hover-border-color: var(--tblr-vimeo);--tblr-btn-active-color: var(--tblr-vimeo-fg);--tblr-btn-active-bg: var(--tblr-vimeo);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-vimeo);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-dribbble{--tblr-btn-color: var(--tblr-dribbble);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-dribbble-fg);--tblr-btn-hover-bg: var(--tblr-dribbble);--tblr-btn-hover-border-color: var(--tblr-dribbble);--tblr-btn-active-color: var(--tblr-dribbble-fg);--tblr-btn-active-bg: var(--tblr-dribbble);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-dribbble);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-github{--tblr-btn-color: var(--tblr-github);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-github-fg);--tblr-btn-hover-bg: var(--tblr-github);--tblr-btn-hover-border-color: var(--tblr-github);--tblr-btn-active-color: var(--tblr-github-fg);--tblr-btn-active-bg: var(--tblr-github);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-github);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-instagram{--tblr-btn-color: var(--tblr-instagram);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-instagram-fg);--tblr-btn-hover-bg: var(--tblr-instagram);--tblr-btn-hover-border-color: var(--tblr-instagram);--tblr-btn-active-color: var(--tblr-instagram-fg);--tblr-btn-active-bg: var(--tblr-instagram);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-instagram);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-pinterest{--tblr-btn-color: var(--tblr-pinterest);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-pinterest-fg);--tblr-btn-hover-bg: var(--tblr-pinterest);--tblr-btn-hover-border-color: var(--tblr-pinterest);--tblr-btn-active-color: var(--tblr-pinterest-fg);--tblr-btn-active-bg: var(--tblr-pinterest);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-pinterest);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-vk{--tblr-btn-color: var(--tblr-vk);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-vk-fg);--tblr-btn-hover-bg: var(--tblr-vk);--tblr-btn-hover-border-color: var(--tblr-vk);--tblr-btn-active-color: var(--tblr-vk-fg);--tblr-btn-active-bg: var(--tblr-vk);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-vk);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-rss{--tblr-btn-color: var(--tblr-rss);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-rss-fg);--tblr-btn-hover-bg: var(--tblr-rss);--tblr-btn-hover-border-color: var(--tblr-rss);--tblr-btn-active-color: var(--tblr-rss-fg);--tblr-btn-active-bg: var(--tblr-rss);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-rss);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-flickr{--tblr-btn-color: var(--tblr-flickr);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-flickr-fg);--tblr-btn-hover-bg: var(--tblr-flickr);--tblr-btn-hover-border-color: var(--tblr-flickr);--tblr-btn-active-color: var(--tblr-flickr-fg);--tblr-btn-active-bg: var(--tblr-flickr);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-flickr);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-bitbucket{--tblr-btn-color: var(--tblr-bitbucket);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-bitbucket-fg);--tblr-btn-hover-bg: var(--tblr-bitbucket);--tblr-btn-hover-border-color: var(--tblr-bitbucket);--tblr-btn-active-color: var(--tblr-bitbucket-fg);--tblr-btn-active-bg: var(--tblr-bitbucket);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-bitbucket);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-ghost-tabler{--tblr-btn-color: var(--tblr-tabler);--tblr-btn-bg: transparent;--tblr-btn-border-color: transparent;--tblr-btn-hover-color: var(--tblr-tabler-fg);--tblr-btn-hover-bg: var(--tblr-tabler);--tblr-btn-hover-border-color: var(--tblr-tabler);--tblr-btn-active-color: var(--tblr-tabler-fg);--tblr-btn-active-bg: var(--tblr-tabler);--tblr-btn-active-border-color: transparent;--tblr-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--tblr-btn-disabled-color: var(--tblr-tabler);--tblr-btn-disabled-bg: transparent;--tblr-btn-disabled-border-color: transparent;--tblr-gradient: none;--tblr-btn-box-shadow: none}.btn-sm,.btn-group-sm>.btn{--tblr-btn-line-height: 1rem;--tblr-btn-icon-size: 1rem}.btn-lg,.btn-group-lg>.btn{--tblr-btn-line-height: 2rem;--tblr-btn-icon-size: 2rem}.btn-pill{padding-right:1.5em;padding-left:1.5em;border-radius:10rem}.btn-pill[class*=btn-icon]{padding:.375rem 15px}.btn-square{border-radius:0}.btn-icon{min-width:calc(var(--tblr-btn-line-height) * var(--tblr-btn-font-size) + var(--tblr-btn-padding-y) * 2 + var(--tblr-btn-border-width) * 2);min-height:calc(var(--tblr-btn-line-height) * var(--tblr-btn-font-size) + var(--tblr-btn-padding-y) * 2 + var(--tblr-btn-border-width) * 2);padding-left:0;padding-right:0}.btn-icon .icon{margin:calc(-1 * var(--tblr-btn-padding-x))}.btn-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.btn-floating{position:fixed;z-index:1030;bottom:1.5rem;right:1.5rem;border-radius:100rem}.btn-loading{position:relative;color:transparent!important;text-shadow:none!important;pointer-events:none}.btn-loading>*{opacity:0}.btn-loading:after{content:"";display:inline-block;vertical-align:text-bottom;border:2px var(--tblr-border-style) currentColor;border-right-color:transparent;border-radius:100rem;color:var(--tblr-btn-color);position:absolute;width:var(--tblr-btn-icon-size);height:var(--tblr-btn-icon-size);left:calc(50% - var(--tblr-btn-icon-size) / 2);top:calc(50% - var(--tblr-btn-icon-size) / 2);animation:spinner-border .75s linear infinite}.btn-action{padding:0;border:0;color:var(--tblr-secondary);display:inline-flex;width:2rem;height:2rem;align-items:center;justify-content:center;border-radius:var(--tblr-border-radius);background:transparent}.btn-action:after{content:none}.btn-action:focus{outline:none;box-shadow:none}.btn-action:hover,.btn-action.show{color:var(--tblr-body-color);background:var(--tblr-active-bg)}.btn-action.show{color:var(--tblr-primary)}.btn-action .icon{margin:0;width:1.25rem;height:1.25rem;font-size:1.25rem;stroke-width:1}.btn-actions{display:flex}.btn-group,.btn-group-vertical{box-shadow:var(--tblr-box-shadow-input)}.btn-group>.btn-check:checked+.btn,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:5}.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus{z-index:1}.calendar{display:block;font-size:.765625rem;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.calendar-nav{display:flex;align-items:center}.calendar-title{flex:1;text-align:center}.calendar-body,.calendar-header{display:flex;flex-wrap:wrap;justify-content:flex-start;padding:.5rem 0}.calendar-header{color:var(--tblr-secondary)}.calendar-date{flex:0 0 14.2857142857%;max-width:14.2857142857%;padding:.2rem;text-align:center;border:0}.calendar-date.prev-month,.calendar-date.next-month{opacity:.25}.calendar-date .date-item{position:relative;display:inline-block;width:1.4rem;height:1.4rem;line-height:1.4rem;color:#66758c;text-align:center;text-decoration:none;white-space:nowrap;vertical-align:middle;cursor:pointer;background:0 0;border:var(--tblr-border-width) var(--tblr-border-style) transparent;border-radius:100rem;outline:0;transition:background .3s,border .3s,box-shadow .32s,color .3s}@media (prefers-reduced-motion: reduce){.calendar-date .date-item{transition:none}}.calendar-date .date-item:hover{color:var(--tblr-primary);text-decoration:none;background:#fefeff;border-color:var(--tblr-border-color)}.calendar-date .date-today{color:var(--tblr-primary);border-color:var(--tblr-border-color)}.calendar-range{position:relative}.calendar-range:before{position:absolute;top:50%;right:0;left:0;height:1.4rem;content:"";background:rgba(var(--tblr-primary-rgb),.1);transform:translateY(-50%)}.calendar-range.range-start .date-item,.calendar-range.range-end .date-item{color:#fff;background:var(--tblr-primary);border-color:var(--tblr-primary)}.calendar-range.range-start:before{left:50%}.calendar-range.range-end:before{right:50%}.carousel-indicators-vertical{left:auto;top:0;margin:0 1rem 0 0;flex-direction:column}.carousel-indicators-vertical [data-bs-target]{margin:3px 0;width:3px;height:30px;border:0;border-left:10px var(--tblr-border-style) transparent;border-right:10px var(--tblr-border-style) transparent}.carousel-indicators-dot [data-bs-target]{width:.5rem;height:.5rem;border-radius:100rem;border:10px var(--tblr-border-style) transparent;margin:0}.carousel-indicators-thumb [data-bs-target]{width:2rem;height:auto;background:no-repeat center/cover;border:0;border-radius:var(--tblr-border-radius);box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px;margin:0 3px;opacity:.75}@media (min-width: 992px){.carousel-indicators-thumb [data-bs-target]{width:4rem}}.carousel-indicators-thumb [data-bs-target]:before{content:"";padding-top:var(--tblr-aspect-ratio, 100%);display:block}.carousel-indicators-thumb.carousel-indicators-vertical [data-bs-target]{margin:3px 0}.carousel-caption-background{background:red;position:absolute;left:0;right:0;bottom:0;height:90%;background:linear-gradient(0deg,#182433e6,#18243300)}.card{transition:transform .3s ease-out,opacity .3s ease-out,box-shadow .3s ease-out}@media (prefers-reduced-motion: reduce){.card{transition:none}}@media print{.card{border:none;box-shadow:none}}a.card{color:inherit}a.card:hover{text-decoration:none;box-shadow:rgba(var(--tblr-body-color-rgb),.16) 0 2px 16px}.card .card{box-shadow:none}.card-borderless,.card-borderless .card-header,.card-borderless .card-footer{border-color:transparent}.card-stamp{--tblr-stamp-size: 7rem;position:absolute;top:0;right:0;width:calc(var(--tblr-stamp-size) * 1);height:calc(var(--tblr-stamp-size) * 1);max-height:100%;border-top-right-radius:4px;opacity:.2;overflow:hidden;pointer-events:none}.card-stamp-lg{--tblr-stamp-size: 13rem}.card-stamp-icon{background:var(--tblr-secondary);color:var(--tblr-card-bg, var(--tblr-bg-surface));display:flex;align-items:center;justify-content:center;border-radius:100rem;width:calc(var(--tblr-stamp-size) * 1);height:calc(var(--tblr-stamp-size) * 1);position:relative;top:calc(var(--tblr-stamp-size) * -.25);right:calc(var(--tblr-stamp-size) * -.25);font-size:calc(var(--tblr-stamp-size) * .75);transform:rotate(10deg)}.card-stamp-icon .icon{stroke-width:2;width:calc(var(--tblr-stamp-size) * .75);height:calc(var(--tblr-stamp-size) * .75)}.card-img,.card-img-start{border-top-left-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)));border-bottom-left-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)))}.card-img,.card-img-end{border-top-right-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)));border-bottom-right-radius:calc(var(--tblr-border-radius) - (var(--tblr-border-width)))}.card-img-overlay{display:flex;flex-direction:column;justify-content:flex-end}.card-img-overlay-dark{background-image:linear-gradient(180deg,#0000,#0009)}.card-inactive{pointer-events:none;box-shadow:none}.card-inactive .card-body{opacity:.64}.card-active{--tblr-card-border-color: var(--tblr-primary);--tblr-card-bg: var(--tblr-active-bg)}.card-btn{display:flex;align-items:center;justify-content:center;padding:1rem 1.25rem;text-align:center;transition:background .3s;border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);flex:1;color:inherit;font-weight:var(--tblr-font-weight-medium)}@media (prefers-reduced-motion: reduce){.card-btn{transition:none}}.card-btn:hover{text-decoration:none;background:rgba(var(--tblr-primary-rgb),.04)}.card-btn+.card-btn{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-stacked{--tblr-card-stacked-offset: .25rem;position:relative}.card-stacked:after{position:absolute;top:calc(-1 * var(--tblr-card-stacked-offset));right:var(--tblr-card-stacked-offset);left:var(--tblr-card-stacked-offset);height:var(--tblr-card-stacked-offset);content:"";background:var(--tblr-card-bg, var(--tblr-bg-surface));border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-card-border-color);border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-cover{position:relative;padding:1rem 1.25rem;background:#666 no-repeat center/cover}.card-cover:before{position:absolute;inset:0;content:"";background:#1824337a}.card-cover:first-child,.card-cover:first-child:before{border-radius:4px 4px 0 0}.card-cover-blurred:before{backdrop-filter:blur(2px)}.card-actions{margin:-.5rem -.5rem -.5rem auto;padding-left:.5rem}.card-actions a{text-decoration:none}.card-header{color:inherit;display:flex;align-items:center;background:transparent}.card-header:first-child{border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-header-light{border-bottom-color:transparent;background:var(--tblr-bg-surface-tertiary)}.card-header-tabs{background:var(--tblr-bg-surface-tertiary);flex:1;margin:calc(var(--tblr-card-cap-padding-y) * -1) calc(var(--tblr-card-cap-padding-x) * -1) calc(var(--tblr-card-cap-padding-y) * -1);padding:calc(var(--tblr-card-cap-padding-y) * .5) calc(var(--tblr-card-cap-padding-x) * .5) 0}.card-header-pills{flex:1;margin-top:-.5rem;margin-bottom:-.5rem}.card-rotate-left{transform:rotate(-1.5deg)}.card-rotate-right{transform:rotate(1.5deg)}.card-link{color:inherit}.card-link:hover{color:inherit;text-decoration:none;box-shadow:0 1px 6px #00000014}.card-link-rotate:hover{transform:rotate(1.5deg);opacity:1}.card-link-pop:hover{transform:translateY(-2px);opacity:1}.card-footer{margin-top:auto}.card-footer:last-child{border-radius:0 0 var(--tblr-card-border-radius) var(--tblr-card-border-radius)}.card-footer-transparent{background:transparent;border-color:transparent;padding-top:0}.card-footer-borderless{border-top:none}.card-progress{height:.25rem}.card-progress:last-child{border-radius:0 0 2px 2px}.card-progress:first-child{border-radius:2px 2px 0 0}.card-meta{color:var(--tblr-secondary)}.card-title{display:block;margin:0 0 1rem;font-size:1rem;font-weight:var(--tblr-font-weight-medium);color:inherit;line-height:1.5rem}a.card-title:hover{color:inherit}.card-header .card-title{margin:0}.card-subtitle{margin-bottom:1.25rem;color:var(--tblr-secondary);font-weight:400}.card-header .card-subtitle{margin:0}.card-title .card-subtitle{margin:0 0 0 .25rem;font-size:.875rem}.card-body{position:relative}.card-body>:last-child{margin-bottom:0}.card-sm>.card-body{padding:1rem}@media (min-width: 768px){.card-md>.card-body{padding:2.5rem}}@media (min-width: 768px){.card-lg>.card-body{padding:2rem}}@media (min-width: 992px){.card-lg>.card-body{padding:4rem}}@media print{.card-body{padding:0}}.card-body+.card-body{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-body-scrollable{overflow:auto}.card-options{top:1.5rem;right:.75rem;display:flex;margin-left:auto}.card-options-link{display:inline-block;min-width:1rem;margin-left:.25rem;color:var(--tblr-secondary)}.card-status-top{position:absolute;top:0;right:0;left:0;height:2px;border-radius:var(--tblr-card-border-radius) var(--tblr-card-border-radius) 0 0}.card-status-start{position:absolute;right:auto;bottom:0;width:2px;height:100%;border-radius:var(--tblr-card-border-radius) 0 0 var(--tblr-card-border-radius)}.card-status-bottom{position:absolute;top:initial;bottom:0;width:100%;height:2px;border-radius:0 0 var(--tblr-card-border-radius) var(--tblr-card-border-radius)}.card-table{margin-bottom:0!important}.card-table tr td:first-child,.card-table tr th:first-child{padding-left:1.25rem;border-left:0}.card-table tr td:last-child,.card-table tr th:last-child{padding-right:1.25rem;border-right:0}.card-table thead tr:first-child,.card-table tbody tr:first-child,.card-table tfoot tr:first-child,.card-table thead tr:first-child td,.card-table thead tr:first-child th,.card-table tbody tr:first-child td,.card-table tbody tr:first-child th,.card-table tfoot tr:first-child td,.card-table tfoot tr:first-child th{border-top:0}.card-body+.card-table{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-table-border-color)}.card-code{padding:0}.card-code .highlight{margin:0;border:0}.card-code pre{margin:0!important;border:0!important}.card-chart{position:relative;z-index:1;height:3.5rem}.card-avatar{margin-left:auto;margin-right:auto;box-shadow:0 0 0 .25rem var(--tblr-card-bg, var(--tblr-bg-surface));margin-top:calc(-1 * var(--tblr-avatar-size) * .5)}.card-body+.card-list-group{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.card-list-group .list-group-item{padding-right:1.25rem;padding-left:1.25rem;border-right:0;border-left:0;border-radius:0}.card-list-group .list-group-item:last-child{border-bottom:0}.card-list-group .list-group-item:first-child{border-top:0}.card-tabs .nav-tabs{position:relative;z-index:1000;border-bottom:0}.card-tabs .nav-tabs .nav-link{background:var(--tblr-bg-surface-tertiary);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.card-tabs .nav-tabs .nav-link.active,.card-tabs .nav-tabs .nav-link:active,.card-tabs .nav-tabs .nav-link:hover{border-color:var(--tblr-border-color-translucent);color:var(--tblr-body-color)}.card-tabs .nav-tabs .nav-link.active{color:inherit;background:var(--tblr-card-bg, var(--tblr-bg-surface));border-bottom-color:transparent}.card-tabs .nav-tabs .nav-item:not(:first-child) .nav-link{border-top-left-radius:0}.card-tabs .nav-tabs .nav-item:not(:last-child) .nav-link{border-top-right-radius:0}.card-tabs .nav-tabs .nav-item+.nav-item{margin-left:calc(-1 * var(--tblr-border-width))}.card-tabs .nav-tabs-bottom,.card-tabs .nav-tabs-bottom .nav-link{margin-bottom:0}.card-tabs .nav-tabs-bottom .nav-link.active{border-top-color:transparent}.card-tabs .nav-tabs-bottom .nav-item{margin-top:calc(-1 * var(--tblr-border-width));margin-bottom:0}.card-tabs .nav-tabs-bottom .nav-item .nav-link{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-radius:0 0 var(--tblr-border-radius) var(--tblr-border-radius)}.card-tabs .nav-tabs-bottom .nav-item:not(:first-child) .nav-link{border-bottom-left-radius:0}.card-tabs .nav-tabs-bottom .nav-item:not(:last-child) .nav-link{border-bottom-right-radius:0}.card-tabs .card{border-bottom-left-radius:0}.card-tabs .nav-tabs+.tab-content .card{border-bottom-left-radius:var(--tblr-card-border-radius);border-top-left-radius:0}.card-note{--tblr-card-bg: #fff7dd;--tblr-card-border-color: #fff1c9}.btn-close{cursor:pointer}.btn-close:focus{outline:none}.dropdown-menu{user-select:none;background-clip:border-box}.dropdown-menu.card{padding:0;min-width:25rem;display:none}.dropdown-menu.card.show{display:flex}.dropdown-item{min-width:11rem;display:flex;align-items:center;margin:0;line-height:1.4285714286}.dropdown-item-icon{width:1.25rem!important;height:1.25rem!important;margin-right:.5rem;color:var(--tblr-secondary);opacity:.7;text-align:center}.dropdown-item-indicator{margin-right:.5rem;margin-left:-.25rem;height:1.25rem;display:inline-flex;line-height:1;vertical-align:bottom;align-items:center}.dropdown-header{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);padding-bottom:.25rem;pointer-events:none}.dropdown-menu-scrollable{height:auto;max-height:13rem;overflow-x:hidden}.dropdown-menu-column{min-width:11rem}.dropdown-menu-column .dropdown-item{min-width:0}.dropdown-menu-columns{display:flex;flex:0 .25rem}.dropdown-menu-arrow:before{content:"";position:absolute;top:-.25rem;left:.75rem;display:block;background:inherit;width:14px;height:14px;transform:rotate(45deg);transform-origin:center;border:1px solid;border-color:inherit;z-index:-1;clip:rect(0px,9px,9px,0px)}.dropdown-menu-arrow.dropdown-menu-end:before{right:.75rem;left:auto}.dropend>.dropdown-menu{margin-top:calc(-.25rem - 1px);margin-left:-.25rem}.dropend .dropdown-toggle:after{margin-left:auto}.dropdown-menu-card{padding:0}.dropdown-menu-card>.card{margin:0;border:0;box-shadow:none}.datagrid{--tblr-datagrid-padding: 1.5rem;--tblr-datagrid-item-width: 15rem;display:grid;grid-gap:var(--tblr-datagrid-padding);grid-template-columns:repeat(auto-fit,minmax(var(--tblr-datagrid-item-width),1fr))}.datagrid-title{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);margin-bottom:.25rem}.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:1rem;text-align:center}@media (min-width: 768px){.empty{padding:3rem}}.empty-icon{margin:0 0 1rem;width:3rem;height:3rem;line-height:1;color:var(--tblr-secondary)}.empty-icon svg{width:100%;height:100%}.empty-img{margin:0 0 2rem;line-height:1}.empty-header{margin:0 0 1rem;font-size:4rem;font-weight:var(--tblr-font-weight-light);line-height:1;color:var(--tblr-secondary)}.empty-title{font-size:1.25rem;line-height:1.75rem;font-weight:var(--tblr-font-weight-bold)}.empty-title,.empty-subtitle{margin:0 0 .5rem}.empty-action{margin-top:1.5rem}.empty-bordered{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.row>*{min-width:0}.col-separator{border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.container-slim{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:16rem}.container-tight{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:30rem}.container-narrow{--tblr-gutter-x: calc(var(--tblr-page-padding) * 2);--tblr-gutter-y: 0;width:100%;padding-right:calc(var(--tblr-gutter-x) * .5);padding-left:calc(var(--tblr-gutter-x) * .5);margin-right:auto;margin-left:auto;max-width:61.875rem}.row-0{margin-right:0;margin-left:0}.row-0>.col,.row-0>[class*=col-]{padding-right:0;padding-left:0}.row-0 .card{margin-bottom:0}.row-sm{margin-right:-.375rem;margin-left:-.375rem}.row-sm>.col,.row-sm>[class*=col-]{padding-right:.375rem;padding-left:.375rem}.row-sm .card{margin-bottom:.75rem}.row-md{margin-right:-1.5rem;margin-left:-1.5rem}.row-md>.col,.row-md>[class*=col-]{padding-right:1.5rem;padding-left:1.5rem}.row-md .card{margin-bottom:3rem}.row-lg{margin-right:-3rem;margin-left:-3rem}.row-lg>.col,.row-lg>[class*=col-]{padding-right:3rem;padding-left:3rem}.row-lg .card{margin-bottom:6rem}.row-deck>.col,.row-deck>[class*=col-]{display:flex;align-items:stretch}.row-deck>.col .card,.row-deck>[class*=col-] .card{flex:1 1 auto}.row-cards{--tblr-gutter-x: var(--tblr-page-padding);--tblr-gutter-y: var(--tblr-page-padding);min-width:0}.row-cards .row-cards{flex:1}.space-y{display:flex;flex-direction:column;gap:1rem}.space-x{display:flex;gap:1rem}.space-y-0{display:flex;flex-direction:column;gap:0}.space-x-0{display:flex;gap:0}.space-y-1{display:flex;flex-direction:column;gap:.25rem}.space-x-1{display:flex;gap:.25rem}.space-y-2{display:flex;flex-direction:column;gap:.5rem}.space-x-2{display:flex;gap:.5rem}.space-y-3{display:flex;flex-direction:column;gap:1rem}.space-x-3{display:flex;gap:1rem}.space-y-4{display:flex;flex-direction:column;gap:1.5rem}.space-x-4{display:flex;gap:1.5rem}.space-y-5{display:flex;flex-direction:column;gap:2rem}.space-x-5{display:flex;gap:2rem}.space-y-6{display:flex;flex-direction:column;gap:2.5rem}.space-x-6{display:flex;gap:2.5rem}.divide-y>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y>:not(template):not(:first-child){padding-top:1rem!important}.divide-y>:not(template):not(:last-child){padding-bottom:1rem!important}.divide-x>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x>:not(template):not(:first-child){padding-left:1rem!important}.divide-x>:not(template):not(:last-child){padding-right:1rem!important}.divide-y-0>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-0>:not(template):not(:first-child){padding-top:0!important}.divide-y-0>:not(template):not(:last-child){padding-bottom:0!important}.divide-x-0>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-0>:not(template):not(:first-child){padding-left:0!important}.divide-x-0>:not(template):not(:last-child){padding-right:0!important}.divide-y-1>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-1>:not(template):not(:first-child){padding-top:.25rem!important}.divide-y-1>:not(template):not(:last-child){padding-bottom:.25rem!important}.divide-x-1>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-1>:not(template):not(:first-child){padding-left:.25rem!important}.divide-x-1>:not(template):not(:last-child){padding-right:.25rem!important}.divide-y-2>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-2>:not(template):not(:first-child){padding-top:.5rem!important}.divide-y-2>:not(template):not(:last-child){padding-bottom:.5rem!important}.divide-x-2>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-2>:not(template):not(:first-child){padding-left:.5rem!important}.divide-x-2>:not(template):not(:last-child){padding-right:.5rem!important}.divide-y-3>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-3>:not(template):not(:first-child){padding-top:1rem!important}.divide-y-3>:not(template):not(:last-child){padding-bottom:1rem!important}.divide-x-3>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-3>:not(template):not(:first-child){padding-left:1rem!important}.divide-x-3>:not(template):not(:last-child){padding-right:1rem!important}.divide-y-4>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-4>:not(template):not(:first-child){padding-top:1.5rem!important}.divide-y-4>:not(template):not(:last-child){padding-bottom:1.5rem!important}.divide-x-4>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-4>:not(template):not(:first-child){padding-left:1.5rem!important}.divide-x-4>:not(template):not(:last-child){padding-right:1.5rem!important}.divide-y-5>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-5>:not(template):not(:first-child){padding-top:2rem!important}.divide-y-5>:not(template):not(:last-child){padding-bottom:2rem!important}.divide-x-5>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-5>:not(template):not(:first-child){padding-left:2rem!important}.divide-x-5>:not(template):not(:last-child){padding-right:2rem!important}.divide-y-6>:not(template)~:not(template){border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-y-6>:not(template):not(:first-child){padding-top:2.5rem!important}.divide-y-6>:not(template):not(:last-child){padding-bottom:2.5rem!important}.divide-x-6>:not(template)~:not(template){border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)!important}.divide-x-6>:not(template):not(:first-child){padding-left:2.5rem!important}.divide-x-6>:not(template):not(:last-child){padding-right:2.5rem!important}.divide-y-fill{display:flex;flex-direction:column;height:100%}.divide-y-fill>:not(template){flex:1;display:flex;justify-content:center;flex-direction:column}.icon{--tblr-icon-size: 1.25rem;width:var(--tblr-icon-size);height:var(--tblr-icon-size);font-size:var(--tblr-icon-size);vertical-align:bottom;stroke-width:1.5}.icon:hover{text-decoration:none}.icon-inline{--tblr-icon-size: 1rem;vertical-align:-.2rem}.icon-filled{fill:currentColor}.icon-sm{--tblr-icon-size: 1rem;stroke-width:1}.icon-md{--tblr-icon-size: 2.5rem;stroke-width:1}.icon-lg{--tblr-icon-size: 3.5rem;stroke-width:1}.icon-pulse{transition:all .15s ease 0s;animation:pulse 2s ease infinite;animation-fill-mode:both}.icon-tada{transition:all .15s ease 0s;animation:tada 3s ease infinite;animation-fill-mode:both}.icon-rotate{transition:all .15s ease 0s;animation:rotate-360 3s linear infinite;animation-fill-mode:both}.img-responsive{--tblr-img-responsive-ratio: 75%;background:no-repeat center/cover;padding-top:var(--tblr-img-responsive-ratio)}.img-responsive-grid{padding-top:calc(var(--tblr-img-responsive-ratio) - var(--tblr-gutter-y) / 2)}.img-responsive-1x1{--tblr-img-responsive-ratio: 100%}.img-responsive-2x1{--tblr-img-responsive-ratio: 50%}.img-responsive-1x2{--tblr-img-responsive-ratio: 200%}.img-responsive-3x1{--tblr-img-responsive-ratio: 33.3333333333%}.img-responsive-1x3{--tblr-img-responsive-ratio: 300%}.img-responsive-4x1{--tblr-img-responsive-ratio: 25%}.img-responsive-1x4{--tblr-img-responsive-ratio: 400%}.img-responsive-4x3{--tblr-img-responsive-ratio: 75%}.img-responsive-3x4{--tblr-img-responsive-ratio: 133.3333333333%}.img-responsive-16x9{--tblr-img-responsive-ratio: 56.25%}.img-responsive-9x16{--tblr-img-responsive-ratio: 177.7777777778%}.img-responsive-21x9{--tblr-img-responsive-ratio: 42.8571428571%}.img-responsive-9x21{--tblr-img-responsive-ratio: 233.3333333333%}.img-bg{background:no-repeat center/cover}textarea[cols]{height:auto}.col-form-label,.form-label{display:block;font-weight:var(--tblr-font-weight-medium)}.col-form-label.required:after,.form-label.required:after{content:"*";margin-left:.25rem;color:#d63939}.form-label-description{float:right;font-weight:var(--tblr-font-weight-normal);color:var(--tblr-gray-500)}.form-hint{display:block;color:var(--tblr-gray-500)}.form-hint:last-child{margin-bottom:0}.form-hint+.form-control{margin-top:.25rem}.form-label+.form-hint{margin-top:-.25rem}.input-group+.form-hint,.form-control+.form-hint,.form-select+.form-hint{margin-top:.5rem;color:var(--tblr-gray-500)}.form-select:-moz-focusring{color:var(--tblr-body-color)}.form-control:-webkit-autofill{box-shadow:0 0 0 1000px var(--tblr-body-bg) inset;color:var(--tblr-body-color);-webkit-text-fill-color:var(--tblr-body-color)}.form-control:disabled,.form-control.disabled{color:var(--tblr-gray-500);user-select:none}.form-control[size]{width:auto}.form-control-light{background-color:var(--tblr-gray-100);border-color:transparent}.form-control-dark{background-color:#0000001a;color:#fff;border-color:transparent}.form-control-dark:focus{background-color:#0000001a;box-shadow:none;border-color:#ffffff3d}.form-control-dark::placeholder{color:#fff9}.form-control-rounded{border-radius:10rem}.form-control-flush{padding:0;background:none!important;border-color:transparent!important;resize:none;box-shadow:none!important;line-height:inherit}.form-footer{margin-top:2rem}.form-fieldset{padding:1rem;margin-bottom:1rem;background:var(--tblr-body-bg);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius)}fieldset:empty{display:none}.form-help{display:inline-flex;font-weight:var(--tblr-font-weight-bold);align-items:center;justify-content:center;width:1.125rem;height:1.125rem;font-size:.75rem;color:var(--tblr-gray-500);text-align:center;text-decoration:none;cursor:pointer;user-select:none;background:var(--tblr-gray-100);border-radius:100rem;transition:background-color .3s,color .3s}@media (prefers-reduced-motion: reduce){.form-help{transition:none}}.form-help:hover,.form-help[aria-describedby]{color:#fff;background:var(--tblr-primary)}.input-group{box-shadow:var(--tblr-box-shadow-input);border-radius:var(--tblr-border-radius)}.input-group .form-control,.input-group .btn{box-shadow:none}.input-group-link{font-size:.75rem}.input-group-flat:focus-within{box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25);border-radius:var(--tblr-border-radius)}.input-group-flat:focus-within .form-control,.input-group-flat:focus-within .input-group-text{border-color:#80c2be!important}.input-group-flat .form-control:focus{border-color:var(--tblr-border-color);box-shadow:none}.input-group-flat .form-control:not(:last-child){border-right:0}.input-group-flat .form-control:not(:first-child){border-left:0}.input-group-flat .input-group-text{background:var(--tblr-bg-forms);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.input-group-flat .input-group-text{transition:none}}.input-group-flat .input-group-text:first-child{padding-right:0}.input-group-flat .input-group-text:last-child{padding-left:0}.form-file-button{margin-left:0;border-left:0}.input-icon{position:relative}.input-icon .form-control:not(:last-child),.input-icon .form-select:not(:last-child){padding-right:2.5rem}.input-icon .form-control:not(:first-child),.input-icon .form-select:not(:last-child){padding-left:2.5rem}.input-icon-addon{position:absolute;top:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;min-width:2.5rem;color:var(--tblr-icon-color);pointer-events:none;font-size:1.2em}.input-icon-addon:last-child{right:0;left:auto}.form-colorinput{position:relative;display:inline-block;margin:0;line-height:1;cursor:pointer}.form-colorinput-input{position:absolute;z-index:-1;opacity:0}.form-colorinput-color{display:block;width:1.5rem;height:1.5rem;color:#fff;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);border-radius:3px;box-shadow:0 1px 2px #0000000d}.form-colorinput-color:before{position:absolute;top:0;left:0;width:100%;height:100%;content:"";background:no-repeat center center/1.25rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e");opacity:0;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-colorinput-color:before{transition:none}}.form-colorinput-input:checked~.form-colorinput-color:before{opacity:1}.form-colorinput-input:focus~.form-colorinput-color{border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-colorinput-light .form-colorinput-color:before{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23182433' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-imagecheck{position:relative;margin:0;cursor:pointer}.form-imagecheck-input{position:absolute;z-index:-1;opacity:0}.form-imagecheck-figure{position:relative;display:block;margin:0;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:3px}.form-imagecheck-input:focus~.form-imagecheck-figure{border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-imagecheck-input:checked~.form-imagecheck-figure{border-color:var(--tblr-primary)}.form-imagecheck-figure:before{position:absolute;top:.25rem;left:.25rem;z-index:1;display:block;width:1.25rem;height:1.25rem;color:#fff;pointer-events:none;content:"";user-select:none;background:var(--tblr-bg-forms);border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:var(--tblr-border-radius);transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-figure:before{transition:none}}.form-imagecheck-input:checked~.form-imagecheck-figure:before{background-color:var(--tblr-primary);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e");background-repeat:repeat;background-position:center;background-size:1.25rem;border-color:var(--tblr-border-color-translucent)}.form-imagecheck-input[type=radio]~.form-imagecheck-figure:before{border-radius:50%}.form-imagecheck-input[type=radio]:checked~.form-imagecheck-figure:before{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-imagecheck-image{max-width:100%;display:block;opacity:.64;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-image{transition:none}}.form-imagecheck-image:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.form-imagecheck-image:last-child{border-bottom-right-radius:2px;border-bottom-left-radius:2px}.form-imagecheck:hover .form-imagecheck-image,.form-imagecheck-input:focus~.form-imagecheck-figure .form-imagecheck-image,.form-imagecheck-input:checked~.form-imagecheck-figure .form-imagecheck-image{opacity:1}.form-imagecheck-caption{padding:.25rem;font-size:.765625rem;color:var(--tblr-secondary);text-align:center;transition:color .3s}@media (prefers-reduced-motion: reduce){.form-imagecheck-caption{transition:none}}.form-imagecheck:hover .form-imagecheck-caption,.form-imagecheck-input:focus~.form-imagecheck-figure .form-imagecheck-caption,.form-imagecheck-input:checked~.form-imagecheck-figure .form-imagecheck-caption{color:var(--tblr-body-color)}.form-selectgroup{display:inline-flex;margin:0 -.5rem -.5rem 0;flex-wrap:wrap}.form-selectgroup .form-selectgroup-item{margin:0 .5rem .5rem 0}.form-selectgroup-vertical{flex-direction:column}.form-selectgroup-item{display:block;position:relative}.form-selectgroup-input{position:absolute;top:0;left:0;z-index:-1;opacity:0}.form-selectgroup-label{position:relative;display:block;min-width:calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2));margin:0;padding:.4375rem .75rem;font-size:.875rem;line-height:1.4285714286;color:var(--tblr-secondary);background:var(--tblr-bg-forms);text-align:center;cursor:pointer;user-select:none;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);border-radius:3px;box-shadow:var(--tblr-box-shadow-input);transition:border-color .3s,background .3s,color .3s}@media (prefers-reduced-motion: reduce){.form-selectgroup-label{transition:none}}.form-selectgroup-label .icon:only-child{margin:0 -.25rem}.form-selectgroup-label:hover{color:var(--tblr-body-color)}.form-selectgroup-check{display:inline-block;width:1.25rem;height:1.25rem;border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);vertical-align:middle;box-shadow:var(--tblr-box-shadow-input)}.form-selectgroup-input[type=checkbox]+.form-selectgroup-label .form-selectgroup-check{border-radius:var(--tblr-border-radius)}.form-selectgroup-input[type=radio]+.form-selectgroup-label .form-selectgroup-check{border-radius:50%}.form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-check{background-color:var(--tblr-primary);background-repeat:repeat;background-position:center;background-size:1.25rem;border-color:var(--tblr-border-color-translucent)}.form-selectgroup-input[type=checkbox]:checked+.form-selectgroup-label .form-selectgroup-check{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e")}.form-selectgroup-input[type=radio]:checked+.form-selectgroup-label .form-selectgroup-check{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3ccircle r='3' fill='%23ffffff' cx='8' cy='8' /%3e%3c/svg%3e")}.form-selectgroup-check-floated{position:absolute;top:.4375rem;right:.4375rem}.form-selectgroup-input:checked+.form-selectgroup-label{z-index:1;color:var(--tblr-primary);background:rgba(var(--tblr-primary-rgb),.04);border-color:var(--tblr-primary)}.form-selectgroup-input:focus+.form-selectgroup-label{z-index:2;color:var(--tblr-primary);border-color:var(--tblr-primary);box-shadow:0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.form-selectgroup-boxes .form-selectgroup-label{text-align:left;padding:1.25rem 1rem;color:inherit}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label{color:inherit}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-title{color:var(--tblr-primary)}.form-selectgroup-boxes .form-selectgroup-input:checked+.form-selectgroup-label .form-selectgroup-label-content{opacity:1}.form-selectgroup-pills{flex-wrap:wrap;align-items:flex-start}.form-selectgroup-pills .form-selectgroup-item{flex-grow:0}.form-selectgroup-pills .form-selectgroup-label{border-radius:50px}.form-control-color::-webkit-color-swatch{border:none}[type=search]::-webkit-search-cancel-button{-webkit-appearance:none}.form-control::file-selector-button{background-color:var(--tblr-btn-color, var(--tblr-tertiary-bg))}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--tblr-btn-color, var(--tblr-secondary-bg))}.form-check{user-select:none}.form-check.form-check-highlight .form-check-input:not(:checked)~.form-check-label{color:var(--tblr-secondary)}.form-check .form-check-label-off{color:var(--tblr-secondary)}.form-check .form-check-input:checked~.form-check-label-off{display:none}.form-check .form-check-input:not(:checked)~.form-check-label-on{display:none}.form-check-input{background-size:1.25rem;margin-top:0rem;box-shadow:var(--tblr-box-shadow-input)}.form-switch .form-check-input{transition:background-color .3s,background-position .3s}@media (prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-check-label{display:block}.form-check-label.required:after{content:"*";margin-left:.25rem;color:#d63939}.form-check-description{display:block;color:var(--tblr-secondary);font-size:.75rem;margin-top:.25rem}.form-check-single,.form-check-single .form-check-input{margin:0}.form-switch .form-check-input{height:1.25rem;margin-top:0rem}.form-switch-lg{padding-left:3.5rem;min-height:1.5rem}.form-switch-lg .form-check-input{height:1.5rem;width:2.75rem;background-size:1.5rem;margin-left:-3.5rem}.form-switch-lg .form-check-label{padding-top:.125rem}.form-check-input:checked{border:none}.form-select.is-invalid-lite,.form-control.is-invalid-lite,.form-select.is-valid-lite,.form-control.is-valid-lite{border-color:var(--tblr-border-color)!important}.legend{--tblr-legend-size: .75em;display:inline-block;background:var(--tblr-border-color);width:var(--tblr-legend-size);height:var(--tblr-legend-size);border-radius:var(--tblr-border-radius-sm);border:1px solid var(--tblr-border-color-translucent)}.list-group{margin-left:0;margin-right:0}.list-group-header{background:var(--tblr-bg-surface-tertiary);padding:.5rem 1.25rem;font-size:.75rem;font-weight:var(--tblr-font-weight-medium);line-height:1;text-transform:uppercase;color:var(--tblr-gray-500);border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.list-group-flush>.list-group-header:last-child{border-bottom-width:0}.list-group-item{background-color:inherit}.list-group-item.active{background-color:rgba(var(--tblr-secondary-rgb),.08);border-left-color:#00857d;border-left-width:2px}.list-group-item:active,.list-group-item:focus,.list-group-item:hover{background-color:rgba(var(--tblr-secondary-rgb),.08)}.list-group-item.disabled,.list-group-item:disabled{color:#6c7a91;background-color:rgba(var(--tblr-secondary-rgb),.08)}.list-bordered .list-item{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);margin-top:-1px}.list-bordered .list-item:first-child{border-top:none}.list-group-hoverable .list-group-item-actions{opacity:0;transition:opacity .3s}@media (prefers-reduced-motion: reduce){.list-group-hoverable .list-group-item-actions{transition:none}}.list-group-hoverable .list-group-item:hover .list-group-item-actions,.list-group-hoverable .list-group-item-actions.show{opacity:1}.list-group-transparent{--tblr-list-group-border-radius: 0;margin:0 -1.25rem}.list-group-transparent .list-group-item{background:none;border:0}.list-group-transparent .list-group-item .icon{color:var(--tblr-secondary)}.list-group-transparent .list-group-item.active{font-weight:var(--tblr-font-weight-bold);color:inherit;background:var(--tblr-active-bg)}.list-group-transparent .list-group-item.active .icon{color:inherit}.list-separated{display:flex;flex-direction:column;gap:1rem}.list-inline{margin:0}.list-inline-item:not(:last-child){margin-right:auto;margin-inline-end:.5rem}.list-inline-dots .list-inline-item+.list-inline-item:before{content:" \b7 ";margin-inline-end:.5rem}.loader{position:relative;display:block;width:2.5rem;height:2.5rem;color:#066fd1;vertical-align:middle}.loader:after{position:absolute;top:0;left:0;width:100%;height:100%;content:"";border:1px var(--tblr-border-style);border-color:transparent;border-top-color:currentColor;border-left-color:currentColor;border-radius:100rem;animation:rotate-360 .6s linear;animation-iteration-count:infinite}.dimmer{position:relative}.dimmer .loader{position:absolute;top:50%;right:0;left:0;display:none;margin:0 auto;transform:translateY(-50%)}.dimmer.active .loader{display:block}.dimmer.active .dimmer-content{pointer-events:none;opacity:.1}@keyframes animated-dots{0%{transform:translate(-100%)}}.animated-dots{display:inline-block;overflow:hidden;vertical-align:bottom}.animated-dots:after{display:inline-block;content:"...";animation:animated-dots 1.2s steps(4,jump-none) infinite}.modal-content>.btn-close,.modal-header>.btn-close{position:absolute;top:0;right:0;width:3.5rem;height:3.5rem;margin:0;padding:0;z-index:10}.modal-body{scrollbar-color:rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}.modal-body::-webkit-scrollbar{width:1rem;height:1rem;transition:background .3s}@media (prefers-reduced-motion: reduce){.modal-body::-webkit-scrollbar{transition:none}}.modal-body::-webkit-scrollbar-thumb{border-radius:1rem;border:5px solid transparent;box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.16)}.modal-body::-webkit-scrollbar-track{background:transparent}.modal-body:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 0 1rem rgba(var(--tblr-scrollbar-color, var(--tblr-body-color-rgb)),.32)}.modal-body::-webkit-scrollbar-corner{background:transparent}.modal-body .modal-title{margin-bottom:1rem}.modal-body+.modal-body{border-top:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.modal-status{position:absolute;top:0;left:0;right:0;height:2px;background:var(--tblr-secondary);border-radius:var(--tblr-border-radius-lg) var(--tblr-border-radius-lg) 0 0}.modal-header{align-items:center;min-height:3.5rem;background:transparent;padding:0 3.5rem 0 1.5rem}.modal-title{font-size:1rem;font-weight:var(--tblr-font-weight-bold);color:inherit;line-height:1.4285714286}.modal-footer{padding-top:.75rem;padding-bottom:.75rem}.modal-blur{backdrop-filter:blur(4px)}.modal-full-width{max-width:none;margin:0 .5rem}.nav-vertical,.nav-vertical .nav{flex-direction:column;flex-wrap:nowrap}.nav-vertical .nav{margin-left:1.25rem;border-left:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);padding-left:.5rem}.nav-vertical .nav-link.active,.nav-vertical .nav-item.show .nav-link{font-weight:var(--tblr-font-weight-bold)}.nav-vertical.nav-pills{margin:0 -.75rem}.nav-bordered{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)}.nav-bordered .nav-item+.nav-item{margin-left:1.25rem}.nav-bordered .nav-link{padding-left:0;padding-right:0;margin:0 0 -var(--tblr-border-width);border:0;border-bottom:2px var(--tblr-border-style) transparent}.nav-bordered .nav-link.active,.nav-bordered .nav-item.show .nav-link{color:var(--tblr-primary);border-color:var(--tblr-primary)}.nav-link{display:flex;transition:color .3s;align-items:center}@media (prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link-toggle{margin-left:auto;padding:0 .25rem;transition:transform .3s}@media (prefers-reduced-motion: reduce){.nav-link-toggle{transition:none}}.nav-link-toggle:after{content:"";display:inline-block;vertical-align:.306em;width:.36em;height:.36em;border-bottom:1px var(--tblr-border-style);border-left:1px var(--tblr-border-style);margin-right:.1em;margin-left:.4em;transform:rotate(-45deg)}.nav-link-toggle:after{margin:0}.nav-link[aria-expanded=true] .nav-link-toggle{transform:rotate(180deg)}.nav-link-icon{width:1.25rem;height:1.25rem;margin-right:.5rem;color:var(--tblr-icon-color)}.nav-link-icon svg{display:block;height:100%}.nav-fill .nav-item .nav-link{justify-content:center}.stars{display:inline-flex;color:#8a97ab;font-size:.75rem}.stars .star:not(:first-child){margin-left:.25rem}.pagination{user-select:none}.page-link{min-width:1.75rem;border-radius:var(--tblr-border-radius)}.page-item{text-align:center}.page-item:not(.active) .page-link:hover{background:transparent}.page-item.page-prev,.page-item.page-next{flex:0 0 50%;text-align:left}.page-item.page-next{margin-left:auto;text-align:right}.page-item-subtitle{margin-bottom:2px;font-size:12px;color:var(--tblr-secondary);text-transform:uppercase}.page-item.disabled .page-item-subtitle{color:var(--tblr-disabled-color)}.page-item-title{font-size:1rem;font-weight:var(--tblr-font-weight-normal);color:var(--tblr-body-color)}.page-link:hover .page-item-title{color:#00857d}.page-item.disabled .page-item-title{color:var(--tblr-disabled-color)}@keyframes progress-indeterminate{0%{right:100%;left:-35%}to,60%{right:-90%;left:100%}}.progress{position:relative;width:100%;line-height:.5rem;appearance:none}.progress::-webkit-progress-bar{background:var(--tblr-progress-bg)}.progress::-webkit-progress-value{background-color:var(--tblr-primary)}.progress::-moz-progress-bar{background-color:var(--tblr-primary)}.progress::-ms-fill{background-color:var(--tblr-primary);border:none}.progress-sm{height:.25rem}.progress-bar{height:100%}.progress-bar-indeterminate:after,.progress-bar-indeterminate:before{position:absolute;top:0;bottom:0;left:0;content:"";background-color:inherit;will-change:left,right}.progress-bar-indeterminate:before{animation:progress-indeterminate 1.5s cubic-bezier(.65,.815,.735,.395) infinite}.progress-separated .progress-bar{box-shadow:0 0 0 2px var(--tblr-card-bg, var(--tblr-bg-surface))}.progressbg{position:relative;padding:.25rem .5rem;display:flex}.progressbg-text{position:relative;z-index:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.progressbg-progress{position:absolute;inset:0;z-index:0;height:100%;background:transparent;pointer-events:none}.progressbg-value{font-weight:var(--tblr-font-weight-medium);margin-left:auto;padding-left:2rem}.ribbon{--tblr-ribbon-margin: .25rem;--tblr-ribbon-border-radius: var(--tblr-border-radius);position:absolute;top:.75rem;right:calc(-1 * var(--tblr-ribbon-margin));z-index:1;padding:.25rem .75rem;font-size:.625rem;font-weight:var(--tblr-font-weight-bold);line-height:1;color:#fff;text-align:center;text-transform:uppercase;background:var(--tblr-primary);border-color:var(--tblr-primary);border-radius:var(--tblr-ribbon-border-radius) 0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius);display:inline-flex;align-items:center;justify-content:center;min-height:2rem;min-width:2rem}.ribbon:before{position:absolute;right:0;bottom:100%;width:0;height:0;content:"";filter:brightness(70%);border:calc(var(--tblr-ribbon-margin) * .5) var(--tblr-border-style);border-color:inherit;border-top-color:transparent;border-right-color:transparent}.ribbon.bg-blue{border-color:var(--tblr-blue)}.ribbon.bg-blue-lt{border-color:rgba(var(--tblr-blue-rgb),.1)!important}.ribbon.bg-azure{border-color:var(--tblr-azure)}.ribbon.bg-azure-lt{border-color:rgba(var(--tblr-azure-rgb),.1)!important}.ribbon.bg-indigo{border-color:var(--tblr-indigo)}.ribbon.bg-indigo-lt{border-color:rgba(var(--tblr-indigo-rgb),.1)!important}.ribbon.bg-purple{border-color:var(--tblr-purple)}.ribbon.bg-purple-lt{border-color:rgba(var(--tblr-purple-rgb),.1)!important}.ribbon.bg-pink{border-color:var(--tblr-pink)}.ribbon.bg-pink-lt{border-color:rgba(var(--tblr-pink-rgb),.1)!important}.ribbon.bg-red{border-color:var(--tblr-red)}.ribbon.bg-red-lt{border-color:rgba(var(--tblr-red-rgb),.1)!important}.ribbon.bg-orange{border-color:var(--tblr-orange)}.ribbon.bg-orange-lt{border-color:rgba(var(--tblr-orange-rgb),.1)!important}.ribbon.bg-yellow{border-color:var(--tblr-yellow)}.ribbon.bg-yellow-lt{border-color:rgba(var(--tblr-yellow-rgb),.1)!important}.ribbon.bg-lime{border-color:var(--tblr-lime)}.ribbon.bg-lime-lt{border-color:rgba(var(--tblr-lime-rgb),.1)!important}.ribbon.bg-green{border-color:var(--tblr-green)}.ribbon.bg-green-lt{border-color:rgba(var(--tblr-green-rgb),.1)!important}.ribbon.bg-teal{border-color:var(--tblr-teal)}.ribbon.bg-teal-lt{border-color:rgba(var(--tblr-teal-rgb),.1)!important}.ribbon.bg-cyan{border-color:var(--tblr-cyan)}.ribbon.bg-cyan-lt{border-color:rgba(var(--tblr-cyan-rgb),.1)!important}.ribbon .icon{width:1.25rem;height:1.25rem;font-size:1.25rem}.ribbon-top{top:calc(-1 * var(--tblr-ribbon-margin));right:.75rem;width:2rem;padding:.5rem 0;border-radius:0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius)}.ribbon-top:before{top:0;right:100%;bottom:auto;border-color:inherit;border-top-color:transparent;border-left-color:transparent}.ribbon-top.ribbon-start{right:auto;left:.75rem}.ribbon-top.ribbon-start:before{top:0;right:100%;left:auto}.ribbon-start{right:auto;left:calc(-1 * var(--tblr-ribbon-margin));border-radius:0 var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius) var(--tblr-ribbon-border-radius)}.ribbon-start:before{top:auto;bottom:100%;left:0;border-color:inherit;border-top-color:transparent;border-left-color:transparent}.ribbon-bottom{top:auto;bottom:.75rem}.ribbon-bookmark{padding-left:.25rem;border-radius:0 0 var(--tblr-ribbon-border-radius) 0}.ribbon-bookmark:after{position:absolute;top:0;right:100%;display:block;width:0;height:0;content:"";border:1rem var(--tblr-border-style);border-color:inherit;border-right-width:0;border-left-color:transparent;border-left-width:.5rem}.ribbon-bookmark.ribbon-left{padding-right:.5rem}.ribbon-bookmark.ribbon-left:after{right:auto;left:100%;border-right-color:transparent;border-right-width:.5rem;border-left-width:0}.ribbon-bookmark.ribbon-top{padding-right:0;padding-bottom:.25rem;padding-left:0;border-radius:0 var(--tblr-ribbon-border-radius) 0 0}.ribbon-bookmark.ribbon-top:after{top:100%;right:0;left:0;border-color:inherit;border-width:1rem;border-top-width:0;border-bottom-color:transparent;border-bottom-width:.5rem}.markdown{line-height:1.7142857143}.markdown>:first-child{margin-top:0}.markdown>:last-child,.markdown>:last-child .highlight{margin-bottom:0}@media (min-width: 768px){.markdown>hr,.markdown>.hr{margin-top:3em;margin-bottom:3em}}.markdown>h1,.markdown>.h1,.markdown>h2,.markdown>.h2,.markdown>h3,.markdown>.h3,.markdown>h4,.markdown>.h4,.markdown>h5,.markdown>.h5,.markdown>h6,.markdown>.h6{font-weight:var(--tblr-font-weight-bold)}.markdown>blockquote{font-size:1rem;margin:1.5rem 0;padding:.5rem 1.5rem}.markdown>img{border-radius:var(--tblr-border-radius)}.placeholder:not(.btn):not([class*=bg-]){background-color:currentColor!important}.placeholder:not(.avatar):not([class*=card-img-]){border-radius:var(--tblr-border-radius)}.steps{--tblr-steps-color: var(--tblr-primary);--tblr-steps-inactive-color: var(--tblr-border-color);--tblr-steps-dot-size: .5rem;--tblr-steps-border-width: 2px;display:flex;flex-wrap:nowrap;width:100%;padding:0;margin:0;list-style:none}.steps-blue{--tblr-steps-color: var(--tblr-blue)}.steps-azure{--tblr-steps-color: var(--tblr-azure)}.steps-indigo{--tblr-steps-color: var(--tblr-indigo)}.steps-purple{--tblr-steps-color: var(--tblr-purple)}.steps-pink{--tblr-steps-color: var(--tblr-pink)}.steps-red{--tblr-steps-color: var(--tblr-red)}.steps-orange{--tblr-steps-color: var(--tblr-orange)}.steps-yellow{--tblr-steps-color: var(--tblr-yellow)}.steps-lime{--tblr-steps-color: var(--tblr-lime)}.steps-green{--tblr-steps-color: var(--tblr-green)}.steps-teal{--tblr-steps-color: var(--tblr-teal)}.steps-cyan{--tblr-steps-color: var(--tblr-cyan)}.step-item{position:relative;flex:1 1 0;min-height:1rem;margin-top:0;color:inherit;text-align:center;cursor:default;padding-top:calc(var(--tblr-steps-dot-size))}a.step-item{cursor:pointer}a.step-item:hover{color:inherit}.step-item:after,.step-item:before{background:var(--tblr-steps-color)}.step-item:not(:last-child):after{position:absolute;left:50%;width:100%;content:"";transform:translateY(-50%)}.step-item:after{top:calc(var(--tblr-steps-dot-size) * .5);height:var(--tblr-steps-border-width)}.step-item:before{content:"";position:absolute;top:0;left:50%;z-index:1;box-sizing:content-box;display:flex;align-items:center;justify-content:center;border-radius:100rem;transform:translate(-50%);color:var(--tblr-white);width:var(--tblr-steps-dot-size);height:var(--tblr-steps-dot-size)}.step-item.active{font-weight:var(--tblr-font-weight-bold)}.step-item.active:after{background:var(--tblr-steps-inactive-color)}.step-item.active~.step-item{color:var(--tblr-disabled-color)}.step-item.active~.step-item:after,.step-item.active~.step-item:before{background:var(--tblr-steps-inactive-color)}.steps-counter{--tblr-steps-dot-size: 1.5rem;counter-reset:steps}.steps-counter .step-item{counter-increment:steps}.steps-counter .step-item:before{content:counter(steps)}.steps-vertical{--tblr-steps-dot-offset: 6px;flex-direction:column}.steps-vertical.steps-counter{--tblr-steps-dot-offset: -2px}.steps-vertical .step-item{text-align:left;padding-top:0;padding-left:calc(var(--tblr-steps-dot-size) + 1rem);min-height:auto}.steps-vertical .step-item:not(:first-child){margin-top:1rem}.steps-vertical .step-item:before{top:var(--tblr-steps-dot-offset);left:0;transform:translate(0)}.steps-vertical .step-item:not(:last-child):after{position:absolute;content:"";transform:translate(-50%);top:var(--tblr-steps-dot-offset);left:calc(var(--tblr-steps-dot-size) * .5);width:var(--tblr-steps-border-width);height:calc(100% + 1rem)}@keyframes status-pulsate-main{40%{transform:scale(1.25)}60%{transform:scale(1.25)}}@keyframes status-pulsate-secondary{10%{transform:scale(1)}30%{transform:scale(3)}80%{transform:scale(3)}to{transform:scale(1)}}@keyframes status-pulsate-tertiary{25%{transform:scale(1)}80%{transform:scale(3);opacity:0}to{transform:scale(3);opacity:0}}.status{--tblr-status-height: 1.5rem;--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145;display:inline-flex;align-items:center;height:var(--tblr-status-height);padding:.25rem .75rem;gap:.5rem;color:var(--tblr-status-color);background:rgba(var(--tblr-status-color-rgb),.1);font-size:.875rem;text-transform:none;letter-spacing:normal;border-radius:100rem;font-weight:var(--tblr-font-weight-medium);line-height:1;margin:0}.status .status-dot{background:var(--tblr-status-color)}.status .icon{font-size:1.25rem}.status-lite{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)!important;background:transparent!important;color:var(--tblr-body-color)!important}.status-primary{--tblr-status-color: #00857D;--tblr-status-color-rgb: 0, 133, 125}.status-secondary{--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145}.status-success{--tblr-status-color: #2fb344;--tblr-status-color-rgb: 47, 179, 68}.status-info{--tblr-status-color: #4299e1;--tblr-status-color-rgb: 66, 153, 225}.status-warning{--tblr-status-color: #f76707;--tblr-status-color-rgb: 247, 103, 7}.status-danger{--tblr-status-color: #d63939;--tblr-status-color-rgb: 214, 57, 57}.status-light{--tblr-status-color: #f6f8fb;--tblr-status-color-rgb: 246, 248, 251}.status-dark{--tblr-status-color: #182433;--tblr-status-color-rgb: 24, 36, 51}.status-muted{--tblr-status-color: #6c7a91;--tblr-status-color-rgb: 108, 122, 145}.status-blue{--tblr-status-color: #066fd1;--tblr-status-color-rgb: 6, 111, 209}.status-azure{--tblr-status-color: #4299e1;--tblr-status-color-rgb: 66, 153, 225}.status-indigo{--tblr-status-color: #4263eb;--tblr-status-color-rgb: 66, 99, 235}.status-purple{--tblr-status-color: #ae3ec9;--tblr-status-color-rgb: 174, 62, 201}.status-pink{--tblr-status-color: #d6336c;--tblr-status-color-rgb: 214, 51, 108}.status-red{--tblr-status-color: #d63939;--tblr-status-color-rgb: 214, 57, 57}.status-orange{--tblr-status-color: #f76707;--tblr-status-color-rgb: 247, 103, 7}.status-yellow{--tblr-status-color: #f59f00;--tblr-status-color-rgb: 245, 159, 0}.status-lime{--tblr-status-color: #74b816;--tblr-status-color-rgb: 116, 184, 22}.status-green{--tblr-status-color: #2fb344;--tblr-status-color-rgb: 47, 179, 68}.status-teal{--tblr-status-color: #0ca678;--tblr-status-color-rgb: 12, 166, 120}.status-cyan{--tblr-status-color: #17a2b8;--tblr-status-color-rgb: 23, 162, 184}.status-x{--tblr-status-color: #000000;--tblr-status-color-rgb: 0, 0, 0}.status-facebook{--tblr-status-color: #1877f2;--tblr-status-color-rgb: 24, 119, 242}.status-twitter{--tblr-status-color: #1da1f2;--tblr-status-color-rgb: 29, 161, 242}.status-linkedin{--tblr-status-color: #0a66c2;--tblr-status-color-rgb: 10, 102, 194}.status-google{--tblr-status-color: #dc4e41;--tblr-status-color-rgb: 220, 78, 65}.status-youtube{--tblr-status-color: #ff0000;--tblr-status-color-rgb: 255, 0, 0}.status-vimeo{--tblr-status-color: #1ab7ea;--tblr-status-color-rgb: 26, 183, 234}.status-dribbble{--tblr-status-color: #ea4c89;--tblr-status-color-rgb: 234, 76, 137}.status-github{--tblr-status-color: #181717;--tblr-status-color-rgb: 24, 23, 23}.status-instagram{--tblr-status-color: #e4405f;--tblr-status-color-rgb: 228, 64, 95}.status-pinterest{--tblr-status-color: #bd081c;--tblr-status-color-rgb: 189, 8, 28}.status-vk{--tblr-status-color: #6383a8;--tblr-status-color-rgb: 99, 131, 168}.status-rss{--tblr-status-color: #ffa500;--tblr-status-color-rgb: 255, 165, 0}.status-flickr{--tblr-status-color: #0063dc;--tblr-status-color-rgb: 0, 99, 220}.status-bitbucket{--tblr-status-color: #0052cc;--tblr-status-color-rgb: 0, 82, 204}.status-tabler{--tblr-status-color: #066fd1;--tblr-status-color-rgb: 6, 111, 209}.status-dot{--tblr-status-dot-color: var(--tblr-status-color, #6c7a91);--tblr-status-size: .5rem;position:relative;display:inline-block;width:var(--tblr-status-size);height:var(--tblr-status-size);background:var(--tblr-status-dot-color);border-radius:100rem}.status-dot-animated:before{content:"";position:absolute;inset:0;z-index:0;background:inherit;border-radius:inherit;opacity:.6;animation:1s linear 2s backwards infinite status-pulsate-tertiary}.status-indicator{--tblr-status-indicator-size: 2.5rem;--tblr-status-indicator-color: var(--tblr-status-color, #6c7a91);display:block;position:relative;width:var(--tblr-status-indicator-size);height:var(--tblr-status-indicator-size)}.status-indicator-circle{--tblr-status-circle-size: .75rem;position:absolute;left:50%;top:50%;margin:calc(var(--tblr-status-circle-size) / -2) 0 0 calc(var(--tblr-status-circle-size) / -2);width:var(--tblr-status-circle-size);height:var(--tblr-status-circle-size);border-radius:100rem;background:var(--tblr-status-color)}.status-indicator-circle:nth-child(1){z-index:3}.status-indicator-circle:nth-child(2){z-index:2;opacity:.1}.status-indicator-circle:nth-child(3){z-index:1;opacity:.3}.status-indicator-animated .status-indicator-circle:nth-child(1){animation:2s linear 1s infinite backwards status-pulsate-main}.status-indicator-animated .status-indicator-circle:nth-child(2){animation:2s linear 1s infinite backwards status-pulsate-secondary}.status-indicator-animated .status-indicator-circle:nth-child(3){animation:2s linear 1s infinite backwards status-pulsate-tertiary}.switch-icon{display:inline-block;line-height:1;border:0;padding:0;background:transparent;width:1.25rem;height:1.25rem;vertical-align:bottom;position:relative;cursor:pointer}.switch-icon.disabled{pointer-events:none;opacity:.4}.switch-icon:focus{outline:none}.switch-icon svg{display:block;width:100%;height:100%}.switch-icon .switch-icon-a,.switch-icon .switch-icon-b{display:block;width:100%;height:100%}.switch-icon .switch-icon-a{opacity:1}.switch-icon .switch-icon-b{position:absolute;top:0;left:0;opacity:0}.switch-icon.active .switch-icon-a{opacity:0}.switch-icon.active .switch-icon-b{opacity:1}.switch-icon-fade .switch-icon-a,.switch-icon-fade .switch-icon-b{transition:opacity .5s}@media (prefers-reduced-motion: reduce){.switch-icon-fade .switch-icon-a,.switch-icon-fade .switch-icon-b{transition:none}}.switch-icon-scale .switch-icon-a,.switch-icon-scale .switch-icon-b{transition:opacity .5s,transform 0s .5s}@media (prefers-reduced-motion: reduce){.switch-icon-scale .switch-icon-a,.switch-icon-scale .switch-icon-b{transition:none}}.switch-icon-scale .switch-icon-b{transform:scale(1.5)}.switch-icon-scale.active .switch-icon-a,.switch-icon-scale.active .switch-icon-b{transition:opacity 0s,transform .5s}@media (prefers-reduced-motion: reduce){.switch-icon-scale.active .switch-icon-a,.switch-icon-scale.active .switch-icon-b{transition:none}}.switch-icon-scale.active .switch-icon-b{transform:scale(1)}.switch-icon-flip{perspective:10em}.switch-icon-flip .switch-icon-a,.switch-icon-flip .switch-icon-b{backface-visibility:hidden;transform-style:preserve-3d;transition:opacity 0s .2s,transform .4s ease-in-out}@media (prefers-reduced-motion: reduce){.switch-icon-flip .switch-icon-a,.switch-icon-flip .switch-icon-b{transition:none}}.switch-icon-flip .switch-icon-a{opacity:1;transform:rotateY(0)}.switch-icon-flip .switch-icon-b{opacity:1;transform:rotateY(-180deg)}.switch-icon-flip.active .switch-icon-a{opacity:1;transform:rotateY(180deg)}.switch-icon-flip.active .switch-icon-b{opacity:1;transform:rotateY(0)}.switch-icon-slide-up,.switch-icon-slide-left,.switch-icon-slide-right,.switch-icon-slide-down{overflow:hidden}.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-a,.switch-icon-slide-down .switch-icon-b{transition:opacity .3s,transform .3s}@media (prefers-reduced-motion: reduce){.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-a,.switch-icon-slide-down .switch-icon-b{transition:none}}.switch-icon-slide-up .switch-icon-a,.switch-icon-slide-left .switch-icon-a,.switch-icon-slide-right .switch-icon-a,.switch-icon-slide-down .switch-icon-a{transform:translateY(0)}.switch-icon-slide-up .switch-icon-b,.switch-icon-slide-left .switch-icon-b,.switch-icon-slide-right .switch-icon-b,.switch-icon-slide-down .switch-icon-b{transform:translateY(100%)}.switch-icon-slide-up.active .switch-icon-a,.switch-icon-slide-left.active .switch-icon-a,.switch-icon-slide-right.active .switch-icon-a,.switch-icon-slide-down.active .switch-icon-a{transform:translateY(-100%)}.switch-icon-slide-up.active .switch-icon-b,.switch-icon-slide-left.active .switch-icon-b,.switch-icon-slide-right.active .switch-icon-b,.switch-icon-slide-down.active .switch-icon-b{transform:translateY(0)}.switch-icon-slide-left .switch-icon-a{transform:translate(0)}.switch-icon-slide-left .switch-icon-b{transform:translate(100%)}.switch-icon-slide-left.active .switch-icon-a{transform:translate(-100%)}.switch-icon-slide-left.active .switch-icon-b,.switch-icon-slide-right .switch-icon-a{transform:translate(0)}.switch-icon-slide-right .switch-icon-b{transform:translate(-100%)}.switch-icon-slide-right.active .switch-icon-a{transform:translate(100%)}.switch-icon-slide-right.active .switch-icon-b{transform:translate(0)}.switch-icon-slide-down .switch-icon-a{transform:translateY(0)}.switch-icon-slide-down .switch-icon-b{transform:translateY(-100%)}.switch-icon-slide-down.active .switch-icon-a{transform:translateY(100%)}.switch-icon-slide-down.active .switch-icon-b{transform:translateY(0)}.table thead th,.markdown>table thead th{background:var(--tblr-bg-surface-tertiary);font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);padding-top:.5rem;padding-bottom:.5rem;white-space:nowrap}@media print{.table thead th,.markdown>table thead th{background:transparent}}.table-responsive .table,.table-responsive .markdown>table{margin-bottom:0}.table-responsive+.card-footer{border-top:0}.table-transparent thead th{background:transparent}.table-nowrap>:not(caption)>*>*{white-space:nowrap}.table-vcenter>:not(caption)>*>*{vertical-align:middle}.table-center>:not(caption)>*>*{text-align:center}.td-truncate{max-width:1px;width:100%}.table-mobile{display:block}.table-mobile thead{display:none}.table-mobile tbody,.table-mobile tr{display:flex;flex-direction:column}.table-mobile td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile .btn{display:block}@media (max-width: 575.98px){.table-mobile-sm{display:block}.table-mobile-sm thead{display:none}.table-mobile-sm tbody,.table-mobile-sm tr{display:flex;flex-direction:column}.table-mobile-sm td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-sm td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-sm tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-sm .btn{display:block}}@media (max-width: 767.98px){.table-mobile-md{display:block}.table-mobile-md thead{display:none}.table-mobile-md tbody,.table-mobile-md tr{display:flex;flex-direction:column}.table-mobile-md td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-md td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-md tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-md .btn{display:block}}@media (max-width: 991.98px){.table-mobile-lg{display:block}.table-mobile-lg thead{display:none}.table-mobile-lg tbody,.table-mobile-lg tr{display:flex;flex-direction:column}.table-mobile-lg td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-lg td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-lg tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-lg .btn{display:block}}@media (max-width: 1199.98px){.table-mobile-xl{display:block}.table-mobile-xl thead{display:none}.table-mobile-xl tbody,.table-mobile-xl tr{display:flex;flex-direction:column}.table-mobile-xl td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-xl td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-xl tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-xl .btn{display:block}}@media (max-width: 1399.98px){.table-mobile-xxl{display:block}.table-mobile-xxl thead{display:none}.table-mobile-xxl tbody,.table-mobile-xxl tr{display:flex;flex-direction:column}.table-mobile-xxl td{display:block;padding:.5rem!important;border:none;color:var(--tblr-body-color)!important}.table-mobile-xxl td[data-label]:before{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);content:attr(data-label);display:block}.table-mobile-xxl tr{border-bottom:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent)}.table-mobile-xxl .btn{display:block}}.table-sort{font:inherit;color:inherit;text-transform:inherit;letter-spacing:inherit;border:0;background:inherit;display:block;width:100%;text-align:inherit;transition:color .3s;margin:-.5rem;padding:.5rem}@media (prefers-reduced-motion: reduce){.table-sort{transition:none}}.table-sort:hover,.table-sort.asc,.table-sort.desc{color:var(--tblr-body-color)}.table-sort:after{content:"";display:inline-flex;width:1rem;height:1rem;vertical-align:bottom;mask-image:url("data:image/svg+xml,");background:currentColor;margin-left:.25rem}.table-sort.asc:after{mask-image:url("data:image/svg+xml,")}.table-sort.desc:after{mask-image:url("data:image/svg+xml,")}.table-borderless thead th{background:transparent}.tag{--tblr-tag-height: 1.5rem;border:1px solid var(--tblr-border-color);display:inline-flex;align-items:center;height:var(--tblr-tag-height);border-radius:var(--tblr-border-radius);padding:0 .5rem;background:var(--tblr-bg-surface);box-shadow:var(--tblr-box-shadow-input);gap:.5rem}.tag .btn-close{margin-right:-.25rem;margin-left:-.125rem;padding:0;width:1rem;height:1rem;font-size:.5rem}.tag-badge{--tblr-badge-font-size: .625rem;--tblr-badge-padding-x: .25rem;--tblr-badge-padding-y: .125rem;margin-right:-.25rem}.tag-avatar,.tag-flag,.tag-payment,.tag-icon,.tag-check{margin-left:-.25rem}.tag-icon{color:var(--tblr-secondary);margin-right:-.125rem;width:1rem;height:1rem}.tag-check{width:1rem;height:1rem;background-size:1rem}.tags-list{--tblr-list-gap: .5rem;display:flex;flex-wrap:wrap;gap:var(--tblr-list-gap)}.toast{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color-translucent);box-shadow:#1824330a 0 2px 4px}.toast .toast-header{user-select:none}.toast button[data-bs-dismiss=toast]{outline:none}.toast-primary{--tblr-toast-color: #00857D}.toast-secondary{--tblr-toast-color: #6c7a91}.toast-success{--tblr-toast-color: #2fb344}.toast-info{--tblr-toast-color: #4299e1}.toast-warning{--tblr-toast-color: #f76707}.toast-danger{--tblr-toast-color: #d63939}.toast-light{--tblr-toast-color: #f6f8fb}.toast-dark{--tblr-toast-color: #182433}.toast-muted{--tblr-toast-color: #6c7a91}.toast-blue{--tblr-toast-color: #066fd1}.toast-azure{--tblr-toast-color: #4299e1}.toast-indigo{--tblr-toast-color: #4263eb}.toast-purple{--tblr-toast-color: #ae3ec9}.toast-pink{--tblr-toast-color: #d6336c}.toast-red{--tblr-toast-color: #d63939}.toast-orange{--tblr-toast-color: #f76707}.toast-yellow{--tblr-toast-color: #f59f00}.toast-lime{--tblr-toast-color: #74b816}.toast-green{--tblr-toast-color: #2fb344}.toast-teal{--tblr-toast-color: #0ca678}.toast-cyan{--tblr-toast-color: #17a2b8}.toast-x{--tblr-toast-color: #000000}.toast-facebook{--tblr-toast-color: #1877f2}.toast-twitter{--tblr-toast-color: #1da1f2}.toast-linkedin{--tblr-toast-color: #0a66c2}.toast-google{--tblr-toast-color: #dc4e41}.toast-youtube{--tblr-toast-color: #ff0000}.toast-vimeo{--tblr-toast-color: #1ab7ea}.toast-dribbble{--tblr-toast-color: #ea4c89}.toast-github{--tblr-toast-color: #181717}.toast-instagram{--tblr-toast-color: #e4405f}.toast-pinterest{--tblr-toast-color: #bd081c}.toast-vk{--tblr-toast-color: #6383a8}.toast-rss{--tblr-toast-color: #ffa500}.toast-flickr{--tblr-toast-color: #0063dc}.toast-bitbucket{--tblr-toast-color: #0052cc}.toast-tabler{--tblr-toast-color: #066fd1}.toolbar{display:flex;flex-wrap:nowrap;flex-shrink:0;margin:0 -.5rem}.toolbar>*{margin:0 .5rem}.tracking{--tblr-tracking-height: 1.5rem;--tblr-tracking-gap-width: .125rem;--tblr-tracking-block-border-radius: var(--tblr-border-radius);display:flex;gap:var(--tblr-tracking-gap-width)}.tracking-squares{--tblr-tracking-block-border-radius: var(--tblr-border-radius-sm)}.tracking-squares .tracking-block{height:auto}.tracking-squares .tracking-block:before{content:"";display:block;padding-top:100%}.tracking-block{flex:1;border-radius:var(--tblr-tracking-block-border-radius);height:var(--tblr-tracking-height);min-width:.25rem;background:var(--tblr-border-color)}.timeline{--tblr-timeline-icon-size: 2.5rem;position:relative;list-style:none;padding:0}.timeline-event{position:relative}.timeline-event:not(:last-child){margin-bottom:var(--tblr-page-padding)}.timeline-event:not(:last-child):before{content:"";position:absolute;top:var(--tblr-timeline-icon-size);left:calc(var(--tblr-timeline-icon-size) / 2);bottom:calc(-1 * var(--tblr-page-padding));width:var(--tblr-border-width);background-color:var(--tblr-border-color);border-radius:var(--tblr-border-radius)}.timeline-event-icon{position:absolute;display:flex;align-items:center;justify-content:center;width:var(--tblr-timeline-icon-size, 2.5rem);height:var(--tblr-timeline-icon-size, 2.5rem);background:var(--tblr-gray-200);color:var(--tblr-secondary);border-radius:var(--tblr-border-radius);z-index:5}.timeline-event-card{margin-left:calc(var(--tblr-timeline-icon-size, 2.5rem) + var(--tblr-page-padding))}.timeline-simple .timeline-event-icon{display:none}.timeline-simple .timeline-event-card{margin-left:0}.hr-text{display:flex;align-items:center;margin:2rem 0;font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary);height:1px}.hr-text:after,.hr-text:before{flex:1 1 auto;height:1px;background-color:var(--tblr-border-color)}.hr-text:before{content:"";margin-right:.5rem}.hr-text:after{content:"";margin-left:.5rem}.hr-text>*:first-child{padding-right:.5rem;padding-left:0;color:var(--tblr-secondary)}.hr-text.hr-text-left:before,.hr-text.hr-text-start:before{content:none}.hr-text.hr-text-left>*:first-child,.hr-text.hr-text-start>*:first-child{padding-right:.5rem;padding-left:.5rem}.hr-text.hr-text-right:before,.hr-text.hr-text-end:before{content:""}.hr-text.hr-text-right:after,.hr-text.hr-text-end:after{content:none}.hr-text.hr-text-right>*:first-child,.hr-text.hr-text-end>*:first-child{padding-right:0;padding-left:.5rem}.card>.hr-text{margin:0}.hr-text-spaceless{margin:-.5rem 0}.lead{line-height:1.4}a{text-decoration-skip-ink:auto}h1 a,h2 a,h3 a,.field-group h2 a,h4 a,h5 a,h6 a,.h1 a,.h2 a,.h3 a,.h4 a,.h5 a,.h6 a,h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover,.h1 a:hover,.h2 a:hover,.h3 a:hover,.h4 a:hover,.h5 a:hover,.h6 a:hover{color:inherit}h1,.h1{font-size:var(--tblr-font-size-h1);line-height:var(--tblr-line-height-h1)}h2,.h2{font-size:var(--tblr-font-size-h2);line-height:var(--tblr-line-height-h2)}h3,.field-group h2,.field-group .h2,.h3{font-size:var(--tblr-font-size-h3);line-height:var(--tblr-line-height-h3)}h4,.h4{font-size:var(--tblr-font-size-h4);line-height:var(--tblr-line-height-h4)}h5,.h5{font-size:var(--tblr-font-size-h5);line-height:var(--tblr-line-height-h5)}h6,.h6{font-size:var(--tblr-font-size-h6);line-height:var(--tblr-line-height-h6)}strong,.strong,b{font-weight:var(--tblr-font-weight-bold)}blockquote{padding-left:1rem;border-left:2px var(--tblr-border-style) var(--tblr-border-color)}blockquote p{margin-bottom:1rem}blockquote cite{display:block;text-align:right}blockquote cite:before{content:"\2014 "}ul,ol{padding-left:1.5rem}hr,.hr{margin:2rem 0}dl dd:last-child{margin-bottom:0}pre{padding:1rem;background:var(--tblr-bg-surface-dark);color:var(--tblr-light);border-radius:var(--tblr-border-radius)}pre code{background:transparent;padding:0}code{background:var(--tblr-code-bg);padding:2px 4px;border-radius:var(--tblr-border-radius)}kbd,.kbd{border:var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color);display:inline-block;box-sizing:border-box;max-width:100%;font-size:var(--tblr-font-size-h5);font-weight:var(--tblr-font-weight-medium);line-height:1;vertical-align:baseline;border-radius:var(--tblr-border-radius)}img{max-width:100%;height:auto}.list-unstyled{margin-left:0}::selection{background-color:rgba(var(--tblr-primary-rgb),.16)}[class^=link-].disabled,[class*=" link-"].disabled{color:var(--tblr-disabled-color)!important;pointer-events:none}a:hover:has(.icon){text-decoration:none}.subheader{font-size:.75rem;font-weight:var(--tblr-font-weight-bold);text-transform:uppercase;letter-spacing:.04em;line-height:1rem;color:var(--tblr-secondary)}.chart{display:block;min-height:10rem}.chart text{font-family:inherit}.chart-sm{height:2.5rem}.chart-lg{height:15rem}.chart-square{height:5.75rem}.chart-sparkline{position:relative;width:4rem;height:2.5rem;line-height:1;min-height:0!important}.chart-sparkline-sm{height:1.5rem}.chart-sparkline-square{width:2.5rem}.chart-sparkline-wide{width:6rem}.chart-sparkline-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:.625rem}.chart-sparkline-label .icon{width:1rem;height:1rem;font-size:1rem}.offcanvas-header{border-bottom:var(--tblr-border-width) var(--tblr-border-style) rgba(4,32,69,.1)}.offcanvas-footer{padding:1.5rem}.offcanvas-title{font-size:1rem;font-weight:var(--tblr-font-weight-medium);line-height:1.5rem}.offcanvas-narrow{width:20rem}.chat-bubbles{display:flex;flex-direction:column;gap:1rem}.chat-bubble{background:var(--tblr-bg-surface-secondary);border-radius:var(--tblr-border-radius-lg);padding:1rem;position:relative}.chat-bubble-me{background-color:var(--tblr-primary-lt);box-shadow:none}.chat-bubble-title{margin-bottom:.25rem}.chat-bubble-author{font-weight:600}.chat-bubble-date{color:var(--tblr-secondary)}.chat-bubble-body>*:last-child{margin-bottom:0}.bg-white-overlay{color:#fff;background-color:#f6f8fb3d}.bg-dark-overlay{color:#fff;background-color:#1824333d}.bg-cover{background-repeat:no-repeat;background-size:cover;background-position:center}.bg-primary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-primary-rgb),var(--tblr-bg-opacity))!important}.bg-primary-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-primary-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-primary-lt-rgb),var(--tblr-bg-opacity))!important}.border-primary{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-primary-rgb),var(--tblr-border-opacity))!important}.bg-secondary{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-secondary-rgb),var(--tblr-bg-opacity))!important}.bg-secondary-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-secondary-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-secondary-lt-rgb),var(--tblr-bg-opacity))!important}.border-secondary{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-secondary-rgb),var(--tblr-border-opacity))!important}.bg-success{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-success-rgb),var(--tblr-bg-opacity))!important}.bg-success-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-success-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-success-lt-rgb),var(--tblr-bg-opacity))!important}.border-success{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-success-rgb),var(--tblr-border-opacity))!important}.bg-info{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-info-rgb),var(--tblr-bg-opacity))!important}.bg-info-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-info-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-info-lt-rgb),var(--tblr-bg-opacity))!important}.border-info{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-info-rgb),var(--tblr-border-opacity))!important}.bg-warning{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-warning-rgb),var(--tblr-bg-opacity))!important}.bg-warning-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-warning-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-warning-lt-rgb),var(--tblr-bg-opacity))!important}.border-warning{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-warning-rgb),var(--tblr-border-opacity))!important}.bg-danger{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-danger-rgb),var(--tblr-bg-opacity))!important}.bg-danger-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-danger-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-danger-lt-rgb),var(--tblr-bg-opacity))!important}.border-danger{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-danger-rgb),var(--tblr-border-opacity))!important}.bg-light{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-light-rgb),var(--tblr-bg-opacity))!important}.bg-light-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-light-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-light-lt-rgb),var(--tblr-bg-opacity))!important}.border-light{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-light-rgb),var(--tblr-border-opacity))!important}.bg-dark{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-dark-rgb),var(--tblr-bg-opacity))!important}.bg-dark-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-dark-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-dark-lt-rgb),var(--tblr-bg-opacity))!important}.border-dark{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-dark-rgb),var(--tblr-border-opacity))!important}.bg-muted{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-muted-rgb),var(--tblr-bg-opacity))!important}.bg-muted-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-muted-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-muted-lt-rgb),var(--tblr-bg-opacity))!important}.border-muted{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-muted-rgb),var(--tblr-border-opacity))!important}.bg-blue{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-blue-rgb),var(--tblr-bg-opacity))!important}.bg-blue-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-blue-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-blue-lt-rgb),var(--tblr-bg-opacity))!important}.border-blue{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-blue-rgb),var(--tblr-border-opacity))!important}.bg-azure{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-azure-rgb),var(--tblr-bg-opacity))!important}.bg-azure-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-azure-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-azure-lt-rgb),var(--tblr-bg-opacity))!important}.border-azure{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-azure-rgb),var(--tblr-border-opacity))!important}.bg-indigo{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-indigo-rgb),var(--tblr-bg-opacity))!important}.bg-indigo-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-indigo-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-indigo-lt-rgb),var(--tblr-bg-opacity))!important}.border-indigo{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-indigo-rgb),var(--tblr-border-opacity))!important}.bg-purple{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-purple-rgb),var(--tblr-bg-opacity))!important}.bg-purple-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-purple-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-purple-lt-rgb),var(--tblr-bg-opacity))!important}.border-purple{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-purple-rgb),var(--tblr-border-opacity))!important}.bg-pink{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-pink-rgb),var(--tblr-bg-opacity))!important}.bg-pink-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-pink-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-pink-lt-rgb),var(--tblr-bg-opacity))!important}.border-pink{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-pink-rgb),var(--tblr-border-opacity))!important}.bg-red{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-red-rgb),var(--tblr-bg-opacity))!important}.bg-red-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-red-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-red-lt-rgb),var(--tblr-bg-opacity))!important}.border-red{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-red-rgb),var(--tblr-border-opacity))!important}.bg-orange{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-orange-rgb),var(--tblr-bg-opacity))!important}.bg-orange-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-orange-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-orange-lt-rgb),var(--tblr-bg-opacity))!important}.border-orange{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-orange-rgb),var(--tblr-border-opacity))!important}.bg-yellow{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-yellow-rgb),var(--tblr-bg-opacity))!important}.bg-yellow-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-yellow-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-yellow-lt-rgb),var(--tblr-bg-opacity))!important}.border-yellow{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-yellow-rgb),var(--tblr-border-opacity))!important}.bg-lime{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-lime-rgb),var(--tblr-bg-opacity))!important}.bg-lime-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-lime-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-lime-lt-rgb),var(--tblr-bg-opacity))!important}.border-lime{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-lime-rgb),var(--tblr-border-opacity))!important}.bg-green{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-green-rgb),var(--tblr-bg-opacity))!important}.bg-green-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-green-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-green-lt-rgb),var(--tblr-bg-opacity))!important}.border-green{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-green-rgb),var(--tblr-border-opacity))!important}.bg-teal{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-teal-rgb),var(--tblr-bg-opacity))!important}.bg-teal-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-teal-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-teal-lt-rgb),var(--tblr-bg-opacity))!important}.border-teal{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-teal-rgb),var(--tblr-border-opacity))!important}.bg-cyan{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-cyan-rgb),var(--tblr-bg-opacity))!important}.bg-cyan-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-cyan-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-cyan-lt-rgb),var(--tblr-bg-opacity))!important}.border-cyan{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-cyan-rgb),var(--tblr-border-opacity))!important}.bg-x{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-x-rgb),var(--tblr-bg-opacity))!important}.bg-x-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-x-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-x-lt-rgb),var(--tblr-bg-opacity))!important}.border-x{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-x-rgb),var(--tblr-border-opacity))!important}.bg-facebook{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-facebook-rgb),var(--tblr-bg-opacity))!important}.bg-facebook-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-facebook-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-facebook-lt-rgb),var(--tblr-bg-opacity))!important}.border-facebook{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-facebook-rgb),var(--tblr-border-opacity))!important}.bg-twitter{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-twitter-rgb),var(--tblr-bg-opacity))!important}.bg-twitter-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-twitter-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-twitter-lt-rgb),var(--tblr-bg-opacity))!important}.border-twitter{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-twitter-rgb),var(--tblr-border-opacity))!important}.bg-linkedin{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-bg-opacity))!important}.bg-linkedin-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-linkedin-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-linkedin-lt-rgb),var(--tblr-bg-opacity))!important}.border-linkedin{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-linkedin-rgb),var(--tblr-border-opacity))!important}.bg-google{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-google-rgb),var(--tblr-bg-opacity))!important}.bg-google-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-google-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-google-lt-rgb),var(--tblr-bg-opacity))!important}.border-google{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-google-rgb),var(--tblr-border-opacity))!important}.bg-youtube{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-youtube-rgb),var(--tblr-bg-opacity))!important}.bg-youtube-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-youtube-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-youtube-lt-rgb),var(--tblr-bg-opacity))!important}.border-youtube{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-youtube-rgb),var(--tblr-border-opacity))!important}.bg-vimeo{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-bg-opacity))!important}.bg-vimeo-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-vimeo-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-vimeo-lt-rgb),var(--tblr-bg-opacity))!important}.border-vimeo{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-vimeo-rgb),var(--tblr-border-opacity))!important}.bg-dribbble{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-bg-opacity))!important}.bg-dribbble-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-dribbble-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-dribbble-lt-rgb),var(--tblr-bg-opacity))!important}.border-dribbble{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-dribbble-rgb),var(--tblr-border-opacity))!important}.bg-github{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-github-rgb),var(--tblr-bg-opacity))!important}.bg-github-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-github-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-github-lt-rgb),var(--tblr-bg-opacity))!important}.border-github{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-github-rgb),var(--tblr-border-opacity))!important}.bg-instagram{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-instagram-rgb),var(--tblr-bg-opacity))!important}.bg-instagram-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-instagram-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-instagram-lt-rgb),var(--tblr-bg-opacity))!important}.border-instagram{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-instagram-rgb),var(--tblr-border-opacity))!important}.bg-pinterest{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-bg-opacity))!important}.bg-pinterest-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-pinterest-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-pinterest-lt-rgb),var(--tblr-bg-opacity))!important}.border-pinterest{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-pinterest-rgb),var(--tblr-border-opacity))!important}.bg-vk{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-vk-rgb),var(--tblr-bg-opacity))!important}.bg-vk-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-vk-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-vk-lt-rgb),var(--tblr-bg-opacity))!important}.border-vk{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-vk-rgb),var(--tblr-border-opacity))!important}.bg-rss{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-rss-rgb),var(--tblr-bg-opacity))!important}.bg-rss-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-rss-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-rss-lt-rgb),var(--tblr-bg-opacity))!important}.border-rss{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-rss-rgb),var(--tblr-border-opacity))!important}.bg-flickr{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-flickr-rgb),var(--tblr-bg-opacity))!important}.bg-flickr-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-flickr-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-flickr-lt-rgb),var(--tblr-bg-opacity))!important}.border-flickr{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-flickr-rgb),var(--tblr-border-opacity))!important}.bg-bitbucket{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-bg-opacity))!important}.bg-bitbucket-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-bitbucket-lt-rgb),var(--tblr-bg-opacity))!important}.border-bitbucket{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-border-opacity))!important}.bg-tabler{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-tabler-rgb),var(--tblr-bg-opacity))!important}.bg-tabler-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-tabler-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-tabler-lt-rgb),var(--tblr-bg-opacity))!important}.border-tabler{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-tabler-rgb),var(--tblr-border-opacity))!important}.bg-white{--tblr-bg-opacity: 1;background-color:rgba(var(--tblr-white-rgb),var(--tblr-bg-opacity))!important}.bg-white-lt{--tblr-bg-opacity: 1;--tblr-text-opacity: 1;color:rgba(var(--tblr-white-rgb),var(--tblr-text-opacity))!important;background-color:rgba(var(--tblr-white-lt-rgb),var(--tblr-bg-opacity))!important}.border-white{--tblr-border-opacity: 1;border-color:rgba(var(--tblr-white-rgb),var(--tblr-border-opacity))!important}.text-primary{--tblr-text-opacity: 1;color:rgba(var(--tblr-primary-rgb),var(--tblr-text-opacity))!important}.text-primary-fg{color:var(--tblr-primary-fg)!important}.text-secondary{--tblr-text-opacity: 1;color:rgba(var(--tblr-secondary-rgb),var(--tblr-text-opacity))!important}.text-secondary-fg{color:var(--tblr-secondary-fg)!important}.text-success{--tblr-text-opacity: 1;color:rgba(var(--tblr-success-rgb),var(--tblr-text-opacity))!important}.text-success-fg{color:var(--tblr-success-fg)!important}.text-info{--tblr-text-opacity: 1;color:rgba(var(--tblr-info-rgb),var(--tblr-text-opacity))!important}.text-info-fg{color:var(--tblr-info-fg)!important}.text-warning{--tblr-text-opacity: 1;color:rgba(var(--tblr-warning-rgb),var(--tblr-text-opacity))!important}.text-warning-fg{color:var(--tblr-warning-fg)!important}.text-danger{--tblr-text-opacity: 1;color:rgba(var(--tblr-danger-rgb),var(--tblr-text-opacity))!important}.text-danger-fg{color:var(--tblr-danger-fg)!important}.text-light{--tblr-text-opacity: 1;color:rgba(var(--tblr-light-rgb),var(--tblr-text-opacity))!important}.text-light-fg{color:var(--tblr-light-fg)!important}.text-dark{--tblr-text-opacity: 1;color:rgba(var(--tblr-dark-rgb),var(--tblr-text-opacity))!important}.text-dark-fg{color:var(--tblr-dark-fg)!important}.text-muted{--tblr-text-opacity: 1;color:rgba(var(--tblr-muted-rgb),var(--tblr-text-opacity))!important}.text-muted-fg{color:var(--tblr-muted-fg)!important}.text-blue{--tblr-text-opacity: 1;color:rgba(var(--tblr-blue-rgb),var(--tblr-text-opacity))!important}.text-blue-fg{color:var(--tblr-blue-fg)!important}.text-azure{--tblr-text-opacity: 1;color:rgba(var(--tblr-azure-rgb),var(--tblr-text-opacity))!important}.text-azure-fg{color:var(--tblr-azure-fg)!important}.text-indigo{--tblr-text-opacity: 1;color:rgba(var(--tblr-indigo-rgb),var(--tblr-text-opacity))!important}.text-indigo-fg{color:var(--tblr-indigo-fg)!important}.text-purple{--tblr-text-opacity: 1;color:rgba(var(--tblr-purple-rgb),var(--tblr-text-opacity))!important}.text-purple-fg{color:var(--tblr-purple-fg)!important}.text-pink{--tblr-text-opacity: 1;color:rgba(var(--tblr-pink-rgb),var(--tblr-text-opacity))!important}.text-pink-fg{color:var(--tblr-pink-fg)!important}.text-red{--tblr-text-opacity: 1;color:rgba(var(--tblr-red-rgb),var(--tblr-text-opacity))!important}.text-red-fg{color:var(--tblr-red-fg)!important}.text-orange{--tblr-text-opacity: 1;color:rgba(var(--tblr-orange-rgb),var(--tblr-text-opacity))!important}.text-orange-fg{color:var(--tblr-orange-fg)!important}.text-yellow{--tblr-text-opacity: 1;color:rgba(var(--tblr-yellow-rgb),var(--tblr-text-opacity))!important}.text-yellow-fg{color:var(--tblr-yellow-fg)!important}.text-lime{--tblr-text-opacity: 1;color:rgba(var(--tblr-lime-rgb),var(--tblr-text-opacity))!important}.text-lime-fg{color:var(--tblr-lime-fg)!important}.text-green{--tblr-text-opacity: 1;color:rgba(var(--tblr-green-rgb),var(--tblr-text-opacity))!important}.text-green-fg{color:var(--tblr-green-fg)!important}.text-teal{--tblr-text-opacity: 1;color:rgba(var(--tblr-teal-rgb),var(--tblr-text-opacity))!important}.text-teal-fg{color:var(--tblr-teal-fg)!important}.text-cyan{--tblr-text-opacity: 1;color:rgba(var(--tblr-cyan-rgb),var(--tblr-text-opacity))!important}.text-cyan-fg{color:var(--tblr-cyan-fg)!important}.text-x{--tblr-text-opacity: 1;color:rgba(var(--tblr-x-rgb),var(--tblr-text-opacity))!important}.text-x-fg{color:var(--tblr-x-fg)!important}.text-facebook{--tblr-text-opacity: 1;color:rgba(var(--tblr-facebook-rgb),var(--tblr-text-opacity))!important}.text-facebook-fg{color:var(--tblr-facebook-fg)!important}.text-twitter{--tblr-text-opacity: 1;color:rgba(var(--tblr-twitter-rgb),var(--tblr-text-opacity))!important}.text-twitter-fg{color:var(--tblr-twitter-fg)!important}.text-linkedin{--tblr-text-opacity: 1;color:rgba(var(--tblr-linkedin-rgb),var(--tblr-text-opacity))!important}.text-linkedin-fg{color:var(--tblr-linkedin-fg)!important}.text-google{--tblr-text-opacity: 1;color:rgba(var(--tblr-google-rgb),var(--tblr-text-opacity))!important}.text-google-fg{color:var(--tblr-google-fg)!important}.text-youtube{--tblr-text-opacity: 1;color:rgba(var(--tblr-youtube-rgb),var(--tblr-text-opacity))!important}.text-youtube-fg{color:var(--tblr-youtube-fg)!important}.text-vimeo{--tblr-text-opacity: 1;color:rgba(var(--tblr-vimeo-rgb),var(--tblr-text-opacity))!important}.text-vimeo-fg{color:var(--tblr-vimeo-fg)!important}.text-dribbble{--tblr-text-opacity: 1;color:rgba(var(--tblr-dribbble-rgb),var(--tblr-text-opacity))!important}.text-dribbble-fg{color:var(--tblr-dribbble-fg)!important}.text-github{--tblr-text-opacity: 1;color:rgba(var(--tblr-github-rgb),var(--tblr-text-opacity))!important}.text-github-fg{color:var(--tblr-github-fg)!important}.text-instagram{--tblr-text-opacity: 1;color:rgba(var(--tblr-instagram-rgb),var(--tblr-text-opacity))!important}.text-instagram-fg{color:var(--tblr-instagram-fg)!important}.text-pinterest{--tblr-text-opacity: 1;color:rgba(var(--tblr-pinterest-rgb),var(--tblr-text-opacity))!important}.text-pinterest-fg{color:var(--tblr-pinterest-fg)!important}.text-vk{--tblr-text-opacity: 1;color:rgba(var(--tblr-vk-rgb),var(--tblr-text-opacity))!important}.text-vk-fg{color:var(--tblr-vk-fg)!important}.text-rss{--tblr-text-opacity: 1;color:rgba(var(--tblr-rss-rgb),var(--tblr-text-opacity))!important}.text-rss-fg{color:var(--tblr-rss-fg)!important}.text-flickr{--tblr-text-opacity: 1;color:rgba(var(--tblr-flickr-rgb),var(--tblr-text-opacity))!important}.text-flickr-fg{color:var(--tblr-flickr-fg)!important}.text-bitbucket{--tblr-text-opacity: 1;color:rgba(var(--tblr-bitbucket-rgb),var(--tblr-text-opacity))!important}.text-bitbucket-fg{color:var(--tblr-bitbucket-fg)!important}.text-tabler{--tblr-text-opacity: 1;color:rgba(var(--tblr-tabler-rgb),var(--tblr-text-opacity))!important}.text-tabler-fg{color:var(--tblr-tabler-fg)!important}.bg-gray-50{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-50-rgb),var(--tblr-bg-opacity))!important}.text-gray-50-fg{color:#f6f8fb!important}.bg-gray-100{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-100-rgb),var(--tblr-bg-opacity))!important}.text-gray-100-fg{color:#eef3f6!important}.bg-gray-200{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-200-rgb),var(--tblr-bg-opacity))!important}.text-gray-200-fg{color:#dce1e7!important}.bg-gray-300{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-300-rgb),var(--tblr-bg-opacity))!important}.text-gray-300-fg{color:#b8c4d4!important}.bg-gray-400{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-400-rgb),var(--tblr-bg-opacity))!important}.text-gray-400-fg{color:#8a97ab!important}.bg-gray-500{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-500-rgb),var(--tblr-bg-opacity))!important}.text-gray-500-fg{color:#6c7a91!important}.bg-gray-600{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-600-rgb),var(--tblr-bg-opacity))!important}.text-gray-600-fg{color:#49566c!important}.bg-gray-700{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-700-rgb),var(--tblr-bg-opacity))!important}.text-gray-700-fg{color:#3a4859!important}.bg-gray-800{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-800-rgb),var(--tblr-bg-opacity))!important}.text-gray-800-fg{color:#182433!important}.bg-gray-900{--tblr-bg-opacity: .1;background-color:rgba(var(--tblr-gray-900-rgb),var(--tblr-bg-opacity))!important}.text-gray-900-fg{color:#040a11!important}.scrollable{overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}.scrollable.hover{overflow-y:hidden}.scrollable.hover>*{margin-top:-1px}.scrollable.hover:hover,.scrollable.hover:focus,.scrollable.hover:active{overflow:visible;overflow-y:auto}.touch .scrollable{overflow-y:auto!important}.scroll-x,.scroll-y{overflow:hidden;-webkit-overflow-scrolling:touch}.scroll-y{overflow-y:auto}.scroll-x{overflow-x:auto}.no-scroll{overflow:hidden}.w-0{width:0!important}.h-0{height:0!important}.w-1{width:.25rem!important}.h-1{height:.25rem!important}.w-2{width:.5rem!important}.h-2{height:.5rem!important}.w-3{width:1rem!important}.h-3{height:1rem!important}.w-4{width:1.5rem!important}.h-4{height:1.5rem!important}.w-5{width:2rem!important}.h-5{height:2rem!important}.w-6{width:2.5rem!important}.h-6{height:2.5rem!important}.w-auto{width:auto!important}.h-auto{height:auto!important}.w-px{width:1px!important}.h-px{height:1px!important}.w-full{width:100%!important}.h-full{height:100%!important}.opacity-0{opacity:0!important}.opacity-5{opacity:.05!important}.opacity-10{opacity:.1!important}.opacity-15{opacity:.15!important}.opacity-20{opacity:.2!important}.opacity-25{opacity:.25!important}.opacity-30{opacity:.3!important}.opacity-35{opacity:.35!important}.opacity-40{opacity:.4!important}.opacity-45{opacity:.45!important}.opacity-50{opacity:.5!important}.opacity-55{opacity:.55!important}.opacity-60{opacity:.6!important}.opacity-65{opacity:.65!important}.opacity-70{opacity:.7!important}.opacity-75{opacity:.75!important}.opacity-80{opacity:.8!important}.opacity-85{opacity:.85!important}.opacity-90{opacity:.9!important}.opacity-95{opacity:.95!important}.opacity-100{opacity:1!important}.hover-shadow-sm:hover{box-shadow:0 .125rem .25rem #00000013!important}.hover-shadow:hover{box-shadow:rgba(var(--tblr-body-color-rgb),.04) 0 2px 4px!important}.hover-shadow-lg:hover{box-shadow:0 1rem 3rem #0000002d!important}.hover-shadow-none:hover{box-shadow:none!important}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.subpixel-antialiased{-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.ts-control{border:1px solid var(--tblr-border-color);padding:.4375rem .75rem;width:100%;overflow:hidden;position:relative;z-index:1;box-sizing:border-box;box-shadow:none;border-radius:var(--tblr-border-radius);display:flex;flex-wrap:wrap}.ts-wrapper.multi.has-items .ts-control{padding:calc(.4375rem - 1px + -0) .75rem calc(.4375rem - 4px + -0)}.full .ts-control{background-color:var(--tblr-bg-forms)}.disabled .ts-control,.disabled .ts-control *{cursor:default!important}.focus .ts-control{box-shadow:none}.ts-control>*{vertical-align:baseline;display:inline-block}.ts-wrapper.multi .ts-control>div{cursor:pointer;margin:0 3px 3px 0;padding:1px 5px;background:#efefef;color:#182433;border:0 solid #dce1e7}.ts-wrapper.multi .ts-control>div.active{background:#00857d;color:#fff;border:0 solid rgba(0,0,0,0)}.ts-wrapper.multi.disabled .ts-control>div,.ts-wrapper.multi.disabled .ts-control>div.active{color:#727272;background:#fff;border:0 solid white}.ts-control>input{flex:1 1 auto;min-width:7rem;display:inline-block!important;padding:0!important;min-height:0!important;max-height:none!important;max-width:100%!important;margin:0!important;text-indent:0!important;border:0 none!important;background:none!important;line-height:inherit!important;user-select:auto!important;box-shadow:none!important}.ts-control>input::-ms-clear{display:none}.ts-control>input:focus{outline:none!important}.has-items .ts-control>input{margin:0 4px!important}.ts-control.rtl{text-align:right}.ts-control.rtl.single .ts-control:after{left:calc(.75rem + 5px);right:auto}.ts-control.rtl .ts-control>input{margin:0 4px 0 -2px!important}.disabled .ts-control{opacity:.5;background-color:var(--tblr-bg-surface-secondary)}.input-hidden .ts-control>input{opacity:0;position:absolute;left:-10000px}.ts-dropdown{position:absolute;top:100%;left:0;width:100%;z-index:10;border:1px solid #d0d0d0;background:#fff;margin:.25rem 0 0;border-top:0 none;box-sizing:border-box;box-shadow:0 1px 3px #0000001a;border-radius:0 0 var(--tblr-border-radius) var(--tblr-border-radius)}.ts-dropdown [data-selectable]{cursor:pointer;overflow:hidden}.ts-dropdown [data-selectable] .highlight{background:#ffed2866;border-radius:1px}.ts-dropdown .option,.ts-dropdown .optgroup-header,.ts-dropdown .no-results,.ts-dropdown .create{padding:3px .75rem}.ts-dropdown .option,.ts-dropdown [data-disabled],.ts-dropdown [data-disabled] [data-selectable].option{cursor:inherit;opacity:.5}.ts-dropdown [data-selectable].option{opacity:1;cursor:pointer}.ts-dropdown .optgroup:first-child .optgroup-header{border-top:0 none}.ts-dropdown .optgroup-header{color:#49566c;background:var(--tblr-bg-surface);cursor:default}.ts-dropdown .active{background-color:rgba(var(--tblr-secondary-rgb),.08);color:inherit}.ts-dropdown .active.create{color:inherit}.ts-dropdown .create{color:#18243380}.ts-dropdown .spinner{display:inline-block;width:30px;height:30px;margin:3px .75rem}.ts-dropdown .spinner:after{content:" ";display:block;width:24px;height:24px;margin:3px;border-radius:50%;border:5px solid #d0d0d0;border-color:#d0d0d0 transparent #d0d0d0 transparent;animation:lds-dual-ring 1.2s linear infinite}@keyframes lds-dual-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ts-dropdown-content{overflow:hidden auto;max-height:200px;scroll-behavior:smooth}.ts-wrapper.plugin-drag_drop .ts-dragging{color:transparent!important}.ts-wrapper.plugin-drag_drop .ts-dragging>*{visibility:hidden!important}.plugin-checkbox_options:not(.rtl) .option input{margin-right:.5rem}.plugin-checkbox_options.rtl .option input{margin-left:.5rem}.plugin-clear_button{--ts-pr-clear-button: 1em}.plugin-clear_button .clear-button{opacity:0;position:absolute;top:50%;transform:translateY(-50%);right:calc(.75rem - 5px);margin-right:0!important;background:transparent!important;transition:opacity .5s;cursor:pointer}.plugin-clear_button.form-select .clear-button,.plugin-clear_button.single .clear-button{right:max(var(--ts-pr-caret),.75rem)}.plugin-clear_button.focus.has-items .clear-button,.plugin-clear_button:not(.disabled):hover.has-items .clear-button{opacity:1}.ts-wrapper .dropdown-header{position:relative;padding:6px .75rem;border-bottom:1px solid #d0d0d0;background:color-mix(#fff,#d0d0d0,85%);border-radius:var(--tblr-border-radius) var(--tblr-border-radius) 0 0}.ts-wrapper .dropdown-header-close{position:absolute;right:.75rem;top:50%;color:#182433;opacity:.4;margin-top:-12px;line-height:20px;font-size:20px!important}.ts-wrapper .dropdown-header-close:hover{color:#000}.plugin-dropdown_input.focus.dropdown-active .ts-control{box-shadow:none;border:1px solid var(--tblr-border-color);box-shadow:var(--tblr-box-shadow-input)}.plugin-dropdown_input .dropdown-input{border:1px solid #d0d0d0;border-width:0 0 1px;display:block;padding:.4375rem .75rem;box-shadow:none;width:100%;background:transparent}.plugin-dropdown_input.focus .ts-dropdown .dropdown-input{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.plugin-dropdown_input .items-placeholder{border:0 none!important;box-shadow:none!important;width:100%}.plugin-dropdown_input.has-items .items-placeholder,.plugin-dropdown_input.dropdown-active .items-placeholder{display:none!important}.ts-wrapper.plugin-input_autogrow.has-items .ts-control>input{min-width:0}.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control>input{flex:none;min-width:4px}.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control>input::placeholder{color:transparent}.ts-dropdown.plugin-optgroup_columns .ts-dropdown-content{display:flex}.ts-dropdown.plugin-optgroup_columns .optgroup{border-right:1px solid #f2f2f2;border-top:0 none;flex-grow:1;flex-basis:0;min-width:0}.ts-dropdown.plugin-optgroup_columns .optgroup:last-child{border-right:0 none}.ts-dropdown.plugin-optgroup_columns .optgroup:before{display:none}.ts-dropdown.plugin-optgroup_columns .optgroup-header{border-top:0 none}.ts-wrapper.plugin-remove_button .item{display:inline-flex;align-items:center}.ts-wrapper.plugin-remove_button .item .remove{color:inherit;text-decoration:none;vertical-align:middle;display:inline-block;padding:0 5px;border-radius:0 2px 2px 0;box-sizing:border-box}.ts-wrapper.plugin-remove_button .item .remove:hover{background:#0000000d}.ts-wrapper.plugin-remove_button.disabled .item .remove:hover{background:none}.ts-wrapper.plugin-remove_button .remove-single{position:absolute;right:0;top:0;font-size:23px}.ts-wrapper.plugin-remove_button:not(.rtl) .item{padding-right:0!important}.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove{border-left:1px solid #dce1e7;margin-left:5px}.ts-wrapper.plugin-remove_button:not(.rtl) .item.active .remove{border-left-color:#0000}.ts-wrapper.plugin-remove_button:not(.rtl).disabled .item .remove{border-left-color:#fff}.ts-wrapper.plugin-remove_button.rtl .item{padding-left:0!important}.ts-wrapper.plugin-remove_button.rtl .item .remove{border-right:1px solid #dce1e7;margin-right:5px}.ts-wrapper.plugin-remove_button.rtl .item.active .remove{border-right-color:#0000}.ts-wrapper.plugin-remove_button.rtl.disabled .item .remove{border-right-color:#fff}:root{--ts-pr-clear-button: 0px;--ts-pr-caret: 0px;--ts-pr-min: .75rem}.ts-wrapper.single .ts-control,.ts-wrapper.single .ts-control input{cursor:pointer}.ts-control:not(.rtl){padding-right:max(var(--ts-pr-min),var(--ts-pr-clear-button) + var(--ts-pr-caret))!important}.ts-control.rtl{padding-left:max(var(--ts-pr-min),var(--ts-pr-clear-button) + var(--ts-pr-caret))!important}.ts-wrapper{position:relative}.ts-dropdown,.ts-control,.ts-control input{color:#182433;font-family:inherit;font-size:inherit;line-height:1.4285714286}.ts-control,.ts-wrapper.single.input-active .ts-control{background:var(--tblr-bg-forms);cursor:text}.ts-hidden-accessible{border:0!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;white-space:nowrap!important}.ts-dropdown,.ts-dropdown.form-control,.ts-dropdown.form-select{height:auto;padding:0;z-index:1000;background:#fff;border:1px solid var(--tblr-border-color-translucent);border-radius:4px;box-shadow:0 6px 12px #0000002d}.ts-dropdown .optgroup-header{font-size:.765625rem;line-height:1.4285714286}.ts-dropdown .optgroup:first-child:before{display:none}.ts-dropdown .optgroup:before{content:" ";display:block;height:0;margin:var(--tblr-spacer-2) 0;overflow:hidden;border-top:1px solid var(--tblr-border-color-translucent);margin-left:-.75rem;margin-right:-.75rem}.ts-dropdown .create{padding-left:.75rem}.ts-dropdown-content{padding:5px 0}.ts-control{box-shadow:var(--tblr-box-shadow-input);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;display:flex;align-items:center}@media (prefers-reduced-motion: reduce){.ts-control{transition:none}}.focus .ts-control{border-color:#80c2be;outline:0;box-shadow:var(--tblr-box-shadow-input),0 0 0 .25rem rgba(var(--tblr-primary-rgb),.25)}.ts-control .item{display:flex;align-items:center}.ts-wrapper.is-invalid,.was-validated .invalid,.was-validated :invalid+.ts-wrapper{border-color:var(--tblr-form-invalid-color)}.ts-wrapper.is-invalid:not(.single),.was-validated .invalid:not(.single),.was-validated :invalid+.ts-wrapper:not(.single){background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-position:right calc(.3571428572em + .21875rem) center;background-size:calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem);background-repeat:no-repeat}.ts-wrapper.is-invalid.single,.was-validated .invalid.single,.was-validated :invalid+.ts-wrapper.single{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23d63939' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cline x1='18' y1='6' x2='6' y2='18'%3e%3c/line%3e%3cline x1='6' y1='6' x2='18' y2='18'%3e%3c/line%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem);background-repeat:no-repeat}.ts-wrapper.is-invalid.focus .ts-control,.was-validated .invalid.focus .ts-control,.was-validated :invalid+.ts-wrapper.focus .ts-control{border-color:var(--tblr-form-invalid-color);box-shadow:0 0 0 .25rem rgba(var(--tblr-form-invalid-color),.25)}.ts-wrapper.is-valid,.was-validated .valid,.was-validated :valid+.ts-wrapper{border-color:var(--tblr-form-valid-color)}.ts-wrapper.is-valid:not(.single),.was-validated .valid:not(.single),.was-validated :valid+.ts-wrapper:not(.single){background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-position:right calc(.3571428572em + .21875rem) center;background-size:calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem);background-repeat:no-repeat}.ts-wrapper.is-valid.single,.was-validated .valid.single,.was-validated :valid+.ts-wrapper.single{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%232fb344' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='20 6 9 17 4 12'%3e%3c/polyline%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.7142857143em + .4375rem) calc(.7142857143em + .4375rem);background-repeat:no-repeat}.ts-wrapper.is-valid.focus .ts-control,.was-validated .valid.focus .ts-control,.was-validated :valid+.ts-wrapper.focus .ts-control{border-color:var(--tblr-form-valid-color);box-shadow:0 0 0 .25rem rgba(var(--tblr-form-valid-color),.25)}.ts-wrapper{min-height:calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2));display:flex}.input-group-sm>.ts-wrapper,.ts-wrapper.form-select-sm,.ts-wrapper.form-control-sm{min-height:calc(1.4285714286em + .125rem + calc(var(--tblr-border-width) * 2))}.input-group-sm>.ts-wrapper .ts-control,.ts-wrapper.form-select-sm .ts-control,.ts-wrapper.form-control-sm .ts-control{border-radius:var(--tblr-border-radius-sm);font-size:.75rem}.input-group-sm>.ts-wrapper.has-items .ts-control,.ts-wrapper.form-select-sm.has-items .ts-control,.ts-wrapper.form-control-sm.has-items .ts-control{font-size:.75rem;padding-bottom:0}.input-group-sm>.ts-wrapper.multi.has-items .ts-control,.ts-wrapper.form-select-sm.multi.has-items .ts-control,.ts-wrapper.form-control-sm.multi.has-items .ts-control{padding-top:calc((calc(1.4285714286em + .125rem + calc(var(--tblr-border-width) * 2)) - 1.4285714286 * .75rem - 4px) / 2)!important}.ts-wrapper.multi.has-items .ts-control{padding-left:calc(.75rem - 5px);--ts-pr-min: calc(.75rem - 5px) }.ts-wrapper.multi .ts-control>div{border-radius:calc(var(--tblr-border-radius) - 1px)}.input-group-lg>.ts-wrapper,.ts-wrapper.form-control-lg,.ts-wrapper.form-select-lg{min-height:calc(1.4285714286em + 1.375rem + calc(var(--tblr-border-width) * 2))}.input-group-lg>.ts-wrapper .ts-control,.ts-wrapper.form-control-lg .ts-control,.ts-wrapper.form-select-lg .ts-control{border-radius:var(--tblr-border-radius-lg);font-size:1.25rem}.ts-wrapper:not(.form-control,.form-select){padding:0;border:none;height:auto;box-shadow:none;background:none}.ts-wrapper:not(.form-control,.form-select).single .ts-control{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='%238a97ab' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px}.ts-wrapper.form-select,.ts-wrapper.single{--ts-pr-caret: 2.25rem}.ts-wrapper.form-control,.ts-wrapper.form-select{padding:0!important;height:auto;box-shadow:none;display:flex}.ts-wrapper.form-control .ts-control,.ts-wrapper.form-control.single.input-active .ts-control,.ts-wrapper.form-select .ts-control,.ts-wrapper.form-select.single.input-active .ts-control{border:none!important}.ts-wrapper.form-control:not(.disabled) .ts-control,.ts-wrapper.form-control:not(.disabled).single.input-active .ts-control,.ts-wrapper.form-select:not(.disabled) .ts-control,.ts-wrapper.form-select:not(.disabled).single.input-active .ts-control{background:transparent!important}.input-group>.ts-wrapper{flex-grow:1;width:1%}.input-group>.ts-wrapper:not(:nth-child(2))>.ts-control{border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.ts-wrapper:not(:last-child)>.ts-control{border-top-right-radius:0;border-bottom-right-radius:0}:root{--ts-pr-clear-button: 0rem;--ts-pr-caret: 0rem}.ts-input,.ts-control{color:inherit}.ts-control .dropdown-menu{width:100%;height:auto}.ts-wrapper .form-control,.ts-wrapper .form-select,.ts-wrapper.form-control,.ts-wrapper.form-select{box-shadow:var(--tblr-box-shadow-input)}.ts-wrapper.is-invalid .ts-control,.ts-wrapper.is-valid .ts-control{--ts-pr-clear-button: 1.5rem}.ts-dropdown{background:var(--tblr-bg-surface);color:var(--tblr-body-color);box-shadow:var(--tblr-box-shadow-dropdown);z-index:1000}.ts-dropdown .option{padding:.5rem .75rem}.ts-control,.ts-control input{color:var(--tblr-body-color)}.ts-control input::placeholder{color:#8a97ab}.ts-wrapper.multi .ts-control>div,.ts-wrapper.multi.disabled .ts-control>div{background:var(--tblr-bg-surface-secondary);border:1px solid var(--tblr-border-color);color:var(--tblr-body-color)}.ts-wrapper.disabled .ts-control{opacity:1}.ts-wrapper.disabled .ts-control>div.item{color:var(--tblr-gray-500)}html{scroll-behavior:auto!important}.table-responsive .dropdown,.table-responsive .btn-group,.table-responsive .btn-group-vertical{position:static}.progress{min-width:80px}hr.dropdown-divider,.dropdown-divider.hr{margin-bottom:.25rem;margin-top:.25rem}.dropdown-item{font-weight:400}*{font-feature-settings:"liga" 0;font-variant-ligatures:none}pre{background-color:transparent;color:inherit}.alert{background:var(--tblr-bg-surface)}.btn{display:inline-block}.btn:focus{border:1px solid var(--tblr-primary-fg);outline:2px solid var(--tblr-primary)!important}.btn-sm,.btn-group-sm>.btn{border-radius:4px}.dropdown-item{display:inline-block}.footer .text-primary{color:#001423!important}.nav-tabs .nav-link{display:inline-block}.page,.page-tabs .nav-tabs .nav-link.active{background-color:var(--tblr-bg-surface-tertiary)!important}.page-body .card .card-header{background:var(--tblr-bg-surface-secondary)!important}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-alert-color: darken(var(--tblr-warning),10%);--tblr-link-color: #00F2D4;--tblr-link-color-rgb: 0,242,212;--tblr-link-hover-color-rgb: 0,242,212;--tblr-secondary: #8a97ab;--tblr-primary: #00F2D4;--tblr-primary-fg: #001423;--tblr-primary-rgb: 0,242,212;--tblr-btn-active-color: #001423}body[data-bs-theme=dark],body[data-bs-theme=dark] body[data-bs-theme=light]{background-color:#001423}body[data-bs-theme=dark] ::selection,body[data-bs-theme=dark] body[data-bs-theme=light] ::selection{background-color:rgba(var(--tblr-primary-rgb),.48)}body[data-bs-theme=dark] .btn-primary,body[data-bs-theme=dark] .bg-primary .card-title,body[data-bs-theme=dark] .bg-primary a,body[data-bs-theme=dark] .bg-primary i,body[data-bs-theme=dark] .text-bg-primary{color:#001423!important}body[data-bs-theme=dark] .card{background:#001423!important}body[data-bs-theme=dark] .navbar,body[data-bs-theme=dark] .page-header{background-color:#001423}body[data-bs-theme=dark] .page,body[data-bs-theme=dark] .page-tabs .nav-tabs .nav-link.active{background-color:#081b2a!important}body[data-bs-theme=dark] .page-link.active,body[data-bs-theme=dark] .active>.page-link{color:#001423}body[data-bs-theme=dark] .text-bg-primary{color:#001423!important}body[data-bs-theme=dark] .text-muted{color:var(--tblr-secondary-color)!important}body[data-bs-theme=dark] .text-secondary{color:#8a97ab!important}body[data-bs-theme=dark] .footer .text-primary{color:#fff!important}body[data-bs-theme=dark] .toast{color:var(--tblr-body-color)}body[data-bs-theme=dark] .table-primary{--tblr-table-bg: rgba(var(--tblr-secondary-rgb), .48);--tblr-table-hover-bg: inherit;--tblr-table-hover-color: inherit}pre code{padding:unset}.dropdown-toggle:after{font-family:Material Design Icons;content:"\f0140";padding-right:9px;border-bottom:none;border-left:none;transform:none;vertical-align:.05em;height:auto}.ts-wrapper.multi .ts-control{padding:7px 7px 3px}.ts-wrapper.multi .ts-control div{margin:0 4px 4px 0}.badge a{color:inherit;text-decoration:none}.page-body .card{margin-bottom:1rem}.page-body .card .card-header,.page-body .card .card-body,.page-body .card .card-footer{padding:.75rem}.page-body .card .card-header{background:var(--tblr-bg-surface-tertiary)}.page-body .card h2.card-header,.page-body .card .card-header.h2{font-size:var(--tblr-font-size-h5);line-height:var(--tblr-line-height-h5);margin-bottom:0}.page-body .card .list-group-item{padding:.5rem .75rem}.page-body .card .table,.page-body .card .markdown>table{margin-bottom:0}form.object-edit{margin:auto;max-width:800px}.col-form-label.required{font-weight:700}.col-form-label.required:after{position:absolute;display:inline-block;margin-left:0;font-family:Material Design Icons;font-size:8px;content:"\f06c4"}.has-errors input,.has-errors select,.has-errors textarea{border:1px solid #d63939}.page{background-color:var(--tblr-bg-surface-secondary)}.page-header{background-color:var(--tblr-bg-surface);min-height:0}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg{padding-bottom:2rem}}.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-link-icon,.navbar-vertical.navbar-expand-lg .navbar-collapse .nav-link-title{color:#001423}.navbar-vertical.navbar-expand-lg .navbar-collapse .text-secondary{color:#00857d!important}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item a{color:#001423}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item .btn-group{visibility:hidden}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover,.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active{background-color:var(--tblr-navbar-active-bg)}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover a,.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active a{text-decoration:none}.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item:hover .btn-group,.navbar-vertical.navbar-expand-lg .navbar-collapse .dropdown-menu .dropdown-item.active .btn-group{visibility:visible}.navbar-vertical.navbar-expand-lg .navbar-nav{z-index:1}@media (max-width: 991.98px){.navbar-vertical.navbar-expand-lg .navbar-brand{padding:.2rem 0}}.navbar-vertical.navbar-expand-lg .navbar-brand a:hover{text-decoration:none}.navbar-vertical.navbar-expand-lg img.motif{bottom:0;display:none;left:0;mask-image:linear-gradient(180deg,#0000,#0000004d);opacity:.5;position:fixed;user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-drag:none;-webkit-user-select:none;-ms-user-select:none;width:18rem}@media (min-width: 992px){.navbar-vertical.navbar-expand-lg img.motif{display:block}}body[data-bs-theme=light] .navbar-vertical.navbar-expand-lg{background:linear-gradient(180deg,#00857d00,#00857d1a),#fff}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg{background:linear-gradient(180deg,#00f2d400,#00f2d41a),#001423}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .nav-item.dropdown.active:after{border-color:#00f2d4!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .nav-link-title,body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .nav-link-icon,body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item a{color:#fff!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item.active,body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .dropdown-item:hover{background-color:#ffffff0f!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg .text-secondary{color:#00f2d4!important}body[data-bs-theme=dark] .navbar-vertical.navbar-expand-lg img.motif{opacity:.25}.progress{height:20px}.progress .progress-label{display:flex;flex-direction:column;justify-content:center;padding-left:.25rem}.table thead th,.markdown>table thead th{font-size:.625rem}table.object-list tbody>tr:last-child>td{border-bottom-width:0}table.object-list th.asc>a:after{content:"\f0140";font-family:Material Design Icons}table.object-list th.desc>a:after{content:"\f0143";font-family:Material Design Icons}table.attr-table th{font-weight:400;width:min-content}table.attr-table th,table.attr-table td{border-bottom-style:dashed}table.attr-table tr:last-child{border-bottom-style:hidden}table.attr-table td{overflow-wrap:anywhere}td pre{margin-bottom:0}table th.orderable a{color:var(--tblr-body-color)}body[data-bs-theme=dark] .table thead th,body[data-bs-theme=dark] .markdown>table thead th{background:#001423!important}.page-tabs{border-bottom:1px solid var(--tblr-border-color-translucent)}.page-tabs .nav-tabs{position:relative;border:none}.page-tabs .nav-tabs .nav-link.active,.page-tabs .nav-tabs .nav-link:active,.page-tabs .nav-tabs .nav-link:hover{border-color:var(--tblr-border-color-translucent);border-bottom-color:transparent}.page-tabs .nav-tabs .nav-link.active{color:inherit;background:var(--tblr-bg-surface-secondary);border-bottom-color:transparent}pre.change-data{border-radius:0;padding:0}pre.change-data>span{display:block;padding-right:1rem;padding-left:1rem}pre.change-data>span.added{background-color:#2fb344}pre.change-data>span.removed{background-color:#d63939}pre.change-diff{border-color:transparent}pre.change-diff.change-added{background-color:#2fb344}pre.change-diff.change-removed{background-color:#d63939}pre.block{padding:1rem;border:1px solid #dce1e7;border-radius:4px}.grid-stack .card-header.bg-default{background:var(--tblr-bg-surface-secondary)!important}.grid-stack .card-header a{color:inherit!important}tr[data-cable-status=connected]{background-color:#2fb34426}tr[data-cable-status=planned]{background-color:#066fd126}tr[data-cable-status=decommissioning]{background-color:#f59f0026}tr[data-mark-connected=true]{background-color:#2fb34426}tr[data-virtual=true]{background-color:#00857d26}tr[data-enabled=disabled]{background-color:#8a97ab26}tr[data-cable-status=connected] button.mark-installed{display:none}tr:not([data-cable-status=connected]) button.mark-planned{display:none}.rendered-markdown table{width:100%}.rendered-markdown table th{border-bottom:2px solid #dddddd;padding:8px}.rendered-markdown table td{border-top:1px solid #dddddd;padding:8px}.rendered-markdown table th[align=left]{text-align:left}.rendered-markdown table th[align=center]{text-align:center}.rendered-markdown table th[align=right]{text-align:right}.rendered-markdown p:last-of-type{margin-bottom:0}td>.rendered-markdown{max-height:200px;overflow-y:scroll}.markdown-widget .preview{border:1px solid #dce1e7;border-radius:4px;min-height:200px}span.color-label{display:inline-block;width:5rem;height:1rem;padding:.25em .5em;border:1px solid #303030;border-radius:4px}.record-depth{display:inline;user-select:none;opacity:33%}.record-depth span:only-of-type,.record-depth span:last-of-type{margin-right:.25rem}.hide-last-child :last-child{visibility:hidden;opacity:0}.netbox-edition{letter-spacing:.15rem}.btn-float-group,.btn-float-group-right,.btn-float-group-left{position:sticky;bottom:10px;z-index:2}.btn-float-group-left{float:left}.btn-float-group-right{float:right}.btn-float{--tblr-btn-bg: var(--tblr-bg-surface-tertiary) !important}.logo{height:80px}.sso-icon{height:24px}tr[data-read=True] td{background-color:var(--tblr-bg-surface-secondary);color:var(--tblr-secondary-color)} diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 7e516f7f485..c93cdc4c46d 100644 --- a/netbox/project-static/dist/netbox.js +++ b/netbox/project-static/dist/netbox.js @@ -1,12 +1,11 @@ -"use strict";(()=>{var Xh=Object.create;var Aa=Object.defineProperty,Jh=Object.defineProperties,Zh=Object.getOwnPropertyDescriptor,ep=Object.getOwnPropertyDescriptors,tp=Object.getOwnPropertyNames,ou=Object.getOwnPropertySymbols,ip=Object.getPrototypeOf,su=Object.prototype.hasOwnProperty,np=Object.prototype.propertyIsEnumerable;var Fl=(ii,ei,ti)=>ei in ii?Aa(ii,ei,{enumerable:!0,configurable:!0,writable:!0,value:ti}):ii[ei]=ti,Di=(ii,ei)=>{for(var ti in ei||(ei={}))su.call(ei,ti)&&Fl(ii,ti,ei[ti]);if(ou)for(var ti of ou(ei))np.call(ei,ti)&&Fl(ii,ti,ei[ti]);return ii},sn=(ii,ei)=>Jh(ii,ep(ei));var au=(ii,ei)=>()=>(ei||ii((ei={exports:{}}).exports,ei),ei.exports),lu=(ii,ei)=>{for(var ti in ei)Aa(ii,ti,{get:ei[ti],enumerable:!0})},rp=(ii,ei,ti,ni)=>{if(ei&&typeof ei=="object"||typeof ei=="function")for(let ri of tp(ei))!su.call(ii,ri)&&ri!==ti&&Aa(ii,ri,{get:()=>ei[ri],enumerable:!(ni=Zh(ei,ri))||ni.enumerable});return ii};var cu=(ii,ei,ti)=>(ti=ii!=null?Xh(ip(ii)):{},rp(ei||!ii||!ii.__esModule?Aa(ti,"default",{value:ii,enumerable:!0}):ti,ii));var en=(ii,ei,ti)=>Fl(ii,typeof ei!="symbol"?ei+"":ei,ti);var co=(ii,ei,ti)=>new Promise((ni,ri)=>{var oi=li=>{try{ai(ti.next(li))}catch(ui){ri(ui)}},si=li=>{try{ai(ti.throw(li))}catch(ui){ri(ui)}},ai=li=>li.done?ni(li.value):Promise.resolve(li.value).then(oi,si);ai((ti=ti.apply(ii,ei)).next())});var Ld=au((exports,module)=>{(function(ii,ei){typeof define=="function"&&define.amd?define([],ei):typeof module=="object"&&module.exports?module.exports=ei():ii.htmx=ii.htmx||ei()})(typeof self!="undefined"?self:exports,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(ii,ei){var ti=dr(ii,ei||"post");return ti.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:!1,scrollBehavior:"smooth",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get"],selfRequestsOnly:!1,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(ii){return new EventSource(ii,{withCredentials:!0})},createWebSocket:function(ii){var ei=new WebSocket(ii,[]);return ei.binaryType=Q.config.wsBinaryType,ei},version:"1.9.12"},r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R},w=["get","post","put","delete","patch"],i=w.map(function(ii){return"[hx-"+ii+"], [data-hx-"+ii+"]"}).join(", "),S=e("head"),q=e("title"),H=e("svg",!0);function e(ii,ei){return new RegExp("<"+ii+"(\\s[^>]*>|>)([\\s\\S]*?)<\\/"+ii+">",ei?"gim":"im")}function d(ii){if(ii==null)return;let ei=NaN;return ii.slice(-2)=="ms"?ei=parseFloat(ii.slice(0,-2)):ii.slice(-1)=="s"?ei=parseFloat(ii.slice(0,-1))*1e3:ii.slice(-1)=="m"?ei=parseFloat(ii.slice(0,-1))*1e3*60:ei=parseFloat(ii),isNaN(ei)?void 0:ei}function ee(ii,ei){return ii.getAttribute&&ii.getAttribute(ei)}function o(ii,ei){return ii.hasAttribute&&(ii.hasAttribute(ei)||ii.hasAttribute("data-"+ei))}function te(ii,ei){return ee(ii,ei)||ee(ii,"data-"+ei)}function u(ii){return ii.parentElement}function re(){return document}function c(ii,ei){for(;ii&&!ei(ii);)ii=u(ii);return ii||null}function L(ii,ei,ti){var ni=te(ei,ti),ri=te(ei,"hx-disinherit");return ii!==ei&&ri&&(ri==="*"||ri.split(" ").indexOf(ti)>=0)?"unset":ni}function ne(ii,ei){var ti=null;if(c(ii,function(ni){return ti=L(ii,ni,ei)}),ti!=="unset")return ti}function h(ii,ei){var ti=ii.matches||ii.matchesSelector||ii.msMatchesSelector||ii.mozMatchesSelector||ii.webkitMatchesSelector||ii.oMatchesSelector;return ti&&ti.call(ii,ei)}function A(ii){var ei=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,ti=ei.exec(ii);return ti?ti[1].toLowerCase():""}function s(ii,ei){for(var ti=new DOMParser,ni=ti.parseFromString(ii,"text/html"),ri=ni.body;ei>0;)ei--,ri=ri.firstChild;return ri==null&&(ri=re().createDocumentFragment()),ri}function N(ii){return/",0),oi=ri.querySelector("template").content;return Q.config.allowScriptTags?oe(oi.querySelectorAll("script"),function(si){Q.config.inlineScriptNonce&&(si.nonce=Q.config.inlineScriptNonce),si.htmxExecuted=navigator.userAgent.indexOf("Firefox")===-1}):oe(oi.querySelectorAll("script"),function(si){_(si)}),oi}switch(ti){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return s(""+ni+"
",1);case"col":return s(""+ni+"
",2);case"tr":return s(""+ni+"
",2);case"td":case"th":return s(""+ni+"
",3);case"script":case"style":return s("
"+ni+"
",1);default:return s(ni,0)}}function ie(ii){ii&&ii()}function I(ii,ei){return Object.prototype.toString.call(ii)==="[object "+ei+"]"}function k(ii){return I(ii,"Function")}function P(ii){return I(ii,"Object")}function ae(ii){var ei="htmx-internal-data",ti=ii[ei];return ti||(ti=ii[ei]={}),ti}function M(ii){var ei=[];if(ii)for(var ti=0;ti=0}function se(ii){return ii.getRootNode&&ii.getRootNode()instanceof window.ShadowRoot?re().body.contains(ii.getRootNode().host):re().body.contains(ii)}function D(ii){return ii.trim().split(/\s+/)}function le(ii,ei){for(var ti in ei)ei.hasOwnProperty(ti)&&(ii[ti]=ei[ti]);return ii}function E(ii){try{return JSON.parse(ii)}catch(ei){return b(ei),null}}function U(){var ii="htmx:localStorageTest";try{return localStorage.setItem(ii,ii),localStorage.removeItem(ii),!0}catch(ei){return!1}}function B(ii){try{var ei=new URL(ii);return ei&&(ii=ei.pathname+ei.search),/^\/$/.test(ii)||(ii=ii.replace(/\/+$/,"")),ii}catch(ti){return ii}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(ii){var ei=Q.on("htmx:load",function(ti){ii(ti.detail.elt)});return ei}function V(){Q.logger=function(ii,ei,ti){console&&console.log(ei,ii,ti)}}function j(){Q.logger=null}function C(ii,ei){return ei?ii.querySelector(ei):C(re(),ii)}function f(ii,ei){return ei?ii.querySelectorAll(ei):f(re(),ii)}function _(ii,ei){ii=p(ii),ei?setTimeout(function(){_(ii),ii=null},ei):ii.parentElement.removeChild(ii)}function z(ii,ei,ti){ii=p(ii),ti?setTimeout(function(){z(ii,ei),ii=null},ti):ii.classList&&ii.classList.add(ei)}function n(ii,ei,ti){ii=p(ii),ti?setTimeout(function(){n(ii,ei),ii=null},ti):ii.classList&&(ii.classList.remove(ei),ii.classList.length===0&&ii.removeAttribute("class"))}function $(ii,ei){ii=p(ii),ii.classList.toggle(ei)}function W(ii,ei){ii=p(ii),oe(ii.parentElement.children,function(ti){n(ti,ei)}),z(ii,ei)}function v(ii,ei){if(ii=p(ii),ii.closest)return ii.closest(ei);do if(ii==null||h(ii,ei))return ii;while(ii=ii&&u(ii));return null}function g(ii,ei){return ii.substring(0,ei.length)===ei}function G(ii,ei){return ii.substring(ii.length-ei.length)===ei}function J(ii){var ei=ii.trim();return g(ei,"<")&&G(ei,"/>")?ei.substring(1,ei.length-2):ei}function Z(ii,ei){return ei.indexOf("closest ")===0?[v(ii,J(ei.substr(8)))]:ei.indexOf("find ")===0?[C(ii,J(ei.substr(5)))]:ei==="next"?[ii.nextElementSibling]:ei.indexOf("next ")===0?[K(ii,J(ei.substr(5)))]:ei==="previous"?[ii.previousElementSibling]:ei.indexOf("previous ")===0?[Y(ii,J(ei.substr(9)))]:ei==="document"?[document]:ei==="window"?[window]:ei==="body"?[document.body]:re().querySelectorAll(J(ei))}var K=function(ii,ei){for(var ti=re().querySelectorAll(ei),ni=0;ni=0;ni--){var ri=ti[ni];if(ri.compareDocumentPosition(ii)===Node.DOCUMENT_POSITION_FOLLOWING)return ri}};function ue(ii,ei){return ei?Z(ii,ei)[0]:Z(re().body,ii)[0]}function p(ii){return I(ii,"String")?C(ii):ii}function ve(ii,ei,ti){return k(ei)?{target:re().body,event:ii,listener:ei}:{target:p(ii),event:ei,listener:ti}}function de(ii,ei,ti){jr(function(){var ri=ve(ii,ei,ti);ri.target.addEventListener(ri.event,ri.listener)});var ni=k(ei);return ni?ei:ti}function ge(ii,ei,ti){return jr(function(){var ni=ve(ii,ei,ti);ni.target.removeEventListener(ni.event,ni.listener)}),k(ei)?ei:ti}var pe=re().createElement("output");function me(ii,ei){var ti=ne(ii,ei);if(ti){if(ti==="this")return[xe(ii,ei)];var ni=Z(ii,ti);return ni.length===0?(b('The selector "'+ti+'" on '+ei+" returned no matches!"),[pe]):ni}}function xe(ii,ei){return c(ii,function(ti){return te(ti,ei)!=null})}function ye(ii){var ei=ne(ii,"hx-target");if(ei)return ei==="this"?xe(ii,"hx-target"):ue(ii,ei);var ti=ae(ii);return ti.boosted?re().body:ii}function be(ii){for(var ei=Q.config.attributesToSettle,ti=0;ti0?(ri=ii.substr(0,ii.indexOf(":")),ni=ii.substr(ii.indexOf(":")+1,ii.length)):ri=ii);var oi=re().querySelectorAll(ni);return oi?(oe(oi,function(si){var ai,li=ei.cloneNode(!0);ai=re().createDocumentFragment(),ai.appendChild(li),Se(ri,si)||(ai=li);var ui={shouldSwap:!0,target:si,fragment:ai};ce(si,"htmx:oobBeforeSwap",ui)&&(si=ui.target,ui.shouldSwap&&Fe(ri,si,si,ai,ti),oe(ti.elts,function(ci){ce(ci,"htmx:oobAfterSwap",ui)}))}),ei.parentNode.removeChild(ei)):(ei.parentNode.removeChild(ei),fe(re().body,"htmx:oobErrorNoTarget",{content:ei})),ii}function Ce(ii,ei,ti){var ni=ne(ii,"hx-select-oob");if(ni)for(var ri=ni.split(","),oi=0;oi0){var oi=ri.replace("'","\\'"),si=ni.tagName.replace(":","\\:"),ai=ii.querySelector(si+"[id='"+oi+"']");if(ai&&ai!==ii){var li=ni.cloneNode();we(ni,ai),ti.tasks.push(function(){we(ni,li)})}}})}function Oe(ii){return function(){n(ii,Q.config.addedClass),zt(ii),Nt(ii),qe(ii),ce(ii,"htmx:load")}}function qe(ii){var ei="[autofocus]",ti=h(ii,ei)?ii:ii.querySelector(ei);ti!=null&&ti.focus()}function a(ii,ei,ti,ni){for(Te(ii,ti,ni);ti.childNodes.length>0;){var ri=ti.firstChild;z(ri,Q.config.addedClass),ii.insertBefore(ri,ei),ri.nodeType!==Node.TEXT_NODE&&ri.nodeType!==Node.COMMENT_NODE&&ni.tasks.push(Oe(ri))}}function He(ii,ei){for(var ti=0;ti-1){var ei=ii.replace(H,""),ti=ei.match(q);if(ti)return ti[2]}}function je(ii,ei,ti,ni,ri,oi){ri.title=Ve(ni);var si=l(ni);if(si)return Ce(ti,si,ri),si=Be(ti,si,oi),Re(si),Fe(ii,ti,ei,si,ri)}function _e(ii,ei,ti){var ni=ii.getResponseHeader(ei);if(ni.indexOf("{")===0){var ri=E(ni);for(var oi in ri)if(ri.hasOwnProperty(oi)){var si=ri[oi];P(si)||(si={value:si}),ce(ti,oi,si)}}else for(var ai=ni.split(","),li=0;li0;){var si=ei[0];if(si==="]"){if(ni--,ni===0){oi===null&&(ri=ri+"true"),ei.shift(),ri+=")})";try{var ai=Tr(ii,function(){return Function(ri)()},function(){return!0});return ai.source=ri,ai}catch(li){return fe(re().body,"htmx:syntax:error",{error:li,source:ri}),null}}}else si==="["&&ni++;Qe(si,oi,ti)?ri+="(("+ti+"."+si+") ? ("+ti+"."+si+") : (window."+si+"))":ri=ri+si,oi=ei.shift()}}}function y(ii,ei){for(var ti="";ii.length>0&&!ei.test(ii[0]);)ti+=ii.shift();return ti}function tt(ii){var ei;return ii.length>0&&Ze.test(ii[0])?(ii.shift(),ei=y(ii,Ke).trim(),ii.shift()):ei=y(ii,x),ei}var rt="input, textarea, select";function nt(ii,ei,ti){var ni=[],ri=Ye(ei);do{y(ri,Je);var oi=ri.length,si=y(ri,/[,\[\s]/);if(si!=="")if(si==="every"){var ai={trigger:"every"};y(ri,Je),ai.pollInterval=d(y(ri,/[,\[\s]/)),y(ri,Je);var li=et(ii,ri,"event");li&&(ai.eventFilter=li),ni.push(ai)}else if(si.indexOf("sse:")===0)ni.push({trigger:"sse",sseEvent:si.substr(4)});else{var ui={trigger:si},li=et(ii,ri,"event");for(li&&(ui.eventFilter=li);ri.length>0&&ri[0]!==",";){y(ri,Je);var ci=ri.shift();if(ci==="changed")ui.changed=!0;else if(ci==="once")ui.once=!0;else if(ci==="consume")ui.consume=!0;else if(ci==="delay"&&ri[0]===":")ri.shift(),ui.delay=d(y(ri,x));else if(ci==="from"&&ri[0]===":"){if(ri.shift(),Ze.test(ri[0]))var di=tt(ri);else{var di=y(ri,x);if(di==="closest"||di==="find"||di==="next"||di==="previous"){ri.shift();var pi=tt(ri);pi.length>0&&(di+=" "+pi)}}ui.from=di}else ci==="target"&&ri[0]===":"?(ri.shift(),ui.target=tt(ri)):ci==="throttle"&&ri[0]===":"?(ri.shift(),ui.throttle=d(y(ri,x))):ci==="queue"&&ri[0]===":"?(ri.shift(),ui.queue=y(ri,x)):ci==="root"&&ri[0]===":"?(ri.shift(),ui[ci]=tt(ri)):ci==="threshold"&&ri[0]===":"?(ri.shift(),ui[ci]=y(ri,x)):fe(ii,"htmx:syntax:error",{token:ri.shift()})}ni.push(ui)}ri.length===oi&&fe(ii,"htmx:syntax:error",{token:ri.shift()}),y(ri,Je)}while(ri[0]===","&&ri.shift());return ti&&(ti[ei]=ni),ni}function it(ii){var ei=te(ii,"hx-trigger"),ti=[];if(ei){var ni=Q.config.triggerSpecsCache;ti=ni&&ni[ei]||nt(ii,ei,ni)}return ti.length>0?ti:h(ii,"form")?[{trigger:"submit"}]:h(ii,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:h(ii,rt)?[{trigger:"change"}]:[{trigger:"click"}]}function at(ii){ae(ii).cancelled=!0}function ot(ii,ei,ti){var ni=ae(ii);ni.timeout=setTimeout(function(){se(ii)&&ni.cancelled!==!0&&(ct(ti,ii,Wt("hx:poll:trigger",{triggerSpec:ti,target:ii}))||ei(ii),ot(ii,ei,ti))},ti.pollInterval)}function st(ii){return location.hostname===ii.hostname&&ee(ii,"href")&&ee(ii,"href").indexOf("#")!==0}function lt(ii,ei,ti){if(ii.tagName==="A"&&st(ii)&&(ii.target===""||ii.target==="_self")||ii.tagName==="FORM"){ei.boosted=!0;var ni,ri;if(ii.tagName==="A")ni="get",ri=ee(ii,"href");else{var oi=ee(ii,"method");ni=oi?oi.toLowerCase():"get",ri=ee(ii,"action")}ti.forEach(function(si){ht(ii,function(ai,li){if(v(ai,Q.config.disableSelector)){m(ai);return}he(ni,ri,ai,li)},ei,si,!0)})}}function ut(ii,ei){return!!((ii.type==="submit"||ii.type==="click")&&(ei.tagName==="FORM"||h(ei,'input[type="submit"], button')&&v(ei,"form")!==null||ei.tagName==="A"&&ei.href&&(ei.getAttribute("href")==="#"||ei.getAttribute("href").indexOf("#")!==0)))}function ft(ii,ei){return ae(ii).boosted&&ii.tagName==="A"&&ei.type==="click"&&(ei.ctrlKey||ei.metaKey)}function ct(ii,ei,ti){var ni=ii.eventFilter;if(ni)try{return ni.call(ei,ti)!==!0}catch(ri){return fe(re().body,"htmx:eventFilter:error",{error:ri,source:ni.source}),!0}return!1}function ht(ii,ei,ti,ni,ri){var oi=ae(ii),si;ni.from?si=Z(ii,ni.from):si=[ii],ni.changed&&si.forEach(function(ai){var li=ae(ai);li.lastValue=ai.value}),oe(si,function(ai){var li=function(ui){if(!se(ii)){ai.removeEventListener(ni.trigger,li);return}if(!ft(ii,ui)&&((ri||ut(ui,ii))&&ui.preventDefault(),!ct(ni,ii,ui))){var ci=ae(ui);if(ci.triggerSpec=ni,ci.handledFor==null&&(ci.handledFor=[]),ci.handledFor.indexOf(ii)<0){if(ci.handledFor.push(ii),ni.consume&&ui.stopPropagation(),ni.target&&ui.target&&!h(ui.target,ni.target))return;if(ni.once){if(oi.triggeredOnce)return;oi.triggeredOnce=!0}if(ni.changed){var di=ae(ai);if(di.lastValue===ai.value)return;di.lastValue=ai.value}if(oi.delayed&&clearTimeout(oi.delayed),oi.throttle)return;ni.throttle>0?oi.throttle||(ei(ii,ui),oi.throttle=setTimeout(function(){oi.throttle=null},ni.throttle)):ni.delay>0?oi.delayed=setTimeout(function(){ei(ii,ui)},ni.delay):(ce(ii,"htmx:trigger"),ei(ii,ui))}}};ti.listenerInfos==null&&(ti.listenerInfos=[]),ti.listenerInfos.push({trigger:ni.trigger,listener:li,on:ai}),ai.addEventListener(ni.trigger,li)})}var vt=!1,dt=null;function gt(){dt||(dt=function(){vt=!0},window.addEventListener("scroll",dt),setInterval(function(){vt&&(vt=!1,oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(ii){pt(ii)}))},200))}function pt(ii){if(!o(ii,"data-hx-revealed")&&X(ii)){ii.setAttribute("data-hx-revealed","true");var ei=ae(ii);ei.initHash?ce(ii,"revealed"):ii.addEventListener("htmx:afterProcessNode",function(ti){ce(ii,"revealed")},{once:!0})}}function mt(ii,ei,ti){for(var ni=D(ti),ri=0;ri=0){var si=wt(ti);setTimeout(function(){xt(ii,ei,ti+1)},si)}},ri.onopen=function(oi){ti=0},ae(ii).webSocket=ri,ri.addEventListener("message",function(oi){if(!yt(ii)){var si=oi.data;R(ii,function(pi){si=pi.transformResponse(si,null,ii)});for(var ai=T(ii),li=l(si),ui=M(li.children),ci=0;ci0){ce(ii,"htmx:validation:halted",si);return}ni.send(JSON.stringify(ci)),ut(ti,ii)&&ti.preventDefault()}):fe(ii,"htmx:noWebSocketSourceError")}function wt(ii){var ei=Q.config.wsReconnectDelay;if(typeof ei=="function")return ei(ii);if(ei==="full-jitter"){var ti=Math.min(ii,6),ni=1e3*Math.pow(2,ti);return ni*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(ii,ei,ti){for(var ni=D(ti),ri=0;ri0?setTimeout(ri,ni):ri()}function Ht(ii,ei,ti){var ni=!1;return oe(w,function(ri){if(o(ii,"hx-"+ri)){var oi=te(ii,"hx-"+ri);ni=!0,ei.path=oi,ei.verb=ri,ti.forEach(function(si){Lt(ii,si,ei,function(ai,li){if(v(ai,Q.config.disableSelector)){m(ai);return}he(ri,oi,ai,li)})})}}),ni}function Lt(ii,ei,ti,ni){if(ei.sseEvent)Rt(ii,ni,ei.sseEvent);else if(ei.trigger==="revealed")gt(),ht(ii,ni,ti,ei),pt(ii);else if(ei.trigger==="intersect"){var ri={};ei.root&&(ri.root=ue(ii,ei.root)),ei.threshold&&(ri.threshold=parseFloat(ei.threshold));var oi=new IntersectionObserver(function(si){for(var ai=0;ai0?(ti.polling=!0,ot(ii,ni,ei)):ht(ii,ni,ti,ei)}function At(ii){if(!ii.htmxExecuted&&Q.config.allowScriptTags&&(ii.type==="text/javascript"||ii.type==="module"||ii.type==="")){var ei=re().createElement("script");oe(ii.attributes,function(ni){ei.setAttribute(ni.name,ni.value)}),ei.textContent=ii.textContent,ei.async=!1,Q.config.inlineScriptNonce&&(ei.nonce=Q.config.inlineScriptNonce);var ti=ii.parentElement;try{ti.insertBefore(ei,ii)}catch(ni){b(ni)}finally{ii.parentElement&&ii.parentElement.removeChild(ii)}}}function Nt(ii){h(ii,"script")&&At(ii),oe(f(ii,"script"),function(ei){At(ei)})}function It(ii){var ei=ii.attributes;if(!ei)return!1;for(var ti=0;ti0;){var si=ni.shift(),ai=si.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);oi===0&&ai?(si.split(":"),ri=ai[1].slice(0,-1),ti[ri]=ai[2]):ti[ri]+=si,oi+=Bt(si)}for(var li in ti)Ft(ii,li,ti[li])}}function jt(ii){Ae(ii);for(var ei=0;eiQ.config.historyCacheSize;)ri.shift();for(;ri.length>0;)try{localStorage.setItem("htmx-history-cache",JSON.stringify(ri));break}catch(ai){fe(re().body,"htmx:historyCacheError",{cause:ai,cache:ri}),ri.shift()}}}function Yt(ii){if(!U())return null;ii=B(ii);for(var ei=E(localStorage.getItem("htmx-history-cache"))||[],ti=0;ti=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",ti);var ni=l(this.response);ni=ni.querySelector("[hx-history-elt],[data-hx-history-elt]")||ni;var ri=Zt(),oi=T(ri),si=Ve(this.response);if(si){var ai=C("title");ai?ai.innerHTML=si:window.document.title=si}Ue(ri,ni,oi),nr(oi.tasks),Jt=ii,ce(re().body,"htmx:historyRestore",{path:ii,cacheMiss:!0,serverResponse:this.response})}else fe(re().body,"htmx:historyCacheMissLoadError",ti)},ei.send()}function ar(ii){er(),ii=ii||location.pathname+location.search;var ei=Yt(ii);if(ei){var ti=l(ei.content),ni=Zt(),ri=T(ni);Ue(ni,ti,ri),nr(ri.tasks),document.title=ei.title,setTimeout(function(){window.scrollTo(0,ei.scroll)},0),Jt=ii,ce(re().body,"htmx:historyRestore",{path:ii,item:ei})}else Q.config.refreshOnHistoryMiss?window.location.reload(!0):ir(ii)}function or(ii){var ei=me(ii,"hx-indicator");return ei==null&&(ei=[ii]),oe(ei,function(ti){var ni=ae(ti);ni.requestCount=(ni.requestCount||0)+1,ti.classList.add.call(ti.classList,Q.config.requestClass)}),ei}function sr(ii){var ei=me(ii,"hx-disabled-elt");return ei==null&&(ei=[]),oe(ei,function(ti){var ni=ae(ti);ni.requestCount=(ni.requestCount||0)+1,ti.setAttribute("disabled","")}),ei}function lr(ii,ei){oe(ii,function(ti){var ni=ae(ti);ni.requestCount=(ni.requestCount||0)-1,ni.requestCount===0&&ti.classList.remove.call(ti.classList,Q.config.requestClass)}),oe(ei,function(ti){var ni=ae(ti);ni.requestCount=(ni.requestCount||0)-1,ni.requestCount===0&&ti.removeAttribute("disabled")})}function ur(ii,ei){for(var ti=0;ti=0}function wr(ii,ei){var ti=ei||ne(ii,"hx-swap"),ni={swapStyle:ae(ii).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(ii).boosted&&!br(ii)&&(ni.show="top"),ti){var ri=D(ti);if(ri.length>0)for(var oi=0;oi0?li.join(":"):null;ni.scroll=ui,ni.scrollTarget=ci}else if(si.indexOf("show:")===0){var di=si.substr(5),li=di.split(":"),pi=li.pop(),ci=li.length>0?li.join(":"):null;ni.show=pi,ni.showTarget=ci}else if(si.indexOf("focus-scroll:")===0){var yi=si.substr(13);ni.focusScroll=yi=="true"}else oi==0?ni.swapStyle=si:b("Unknown modifier in hx-swap: "+si)}}return ni}function Sr(ii){return ne(ii,"hx-encoding")==="multipart/form-data"||h(ii,"form")&&ee(ii,"enctype")==="multipart/form-data"}function Er(ii,ei,ti){var ni=null;return R(ei,function(ri){ni==null&&(ni=ri.encodeParameters(ii,ti,ei))}),ni!=null?ni:Sr(ei)?mr(ti):pr(ti)}function T(ii){return{tasks:[],elts:[ii]}}function Cr(ii,ei){var ti=ii[0],ni=ii[ii.length-1];if(ei.scroll){var ri=null;ei.scrollTarget&&(ri=ue(ti,ei.scrollTarget)),ei.scroll==="top"&&(ti||ri)&&(ri=ri||ti,ri.scrollTop=0),ei.scroll==="bottom"&&(ni||ri)&&(ri=ri||ni,ri.scrollTop=ri.scrollHeight)}if(ei.show){var ri=null;if(ei.showTarget){var oi=ei.showTarget;ei.showTarget==="window"&&(oi="body"),ri=ue(ti,oi)}ei.show==="top"&&(ti||ri)&&(ri=ri||ti,ri.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})),ei.show==="bottom"&&(ni||ri)&&(ri=ri||ni,ri.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior}))}}function Rr(ii,ei,ti,ni){if(ni==null&&(ni={}),ii==null)return ni;var ri=te(ii,ei);if(ri){var oi=ri.trim(),si=ti;if(oi==="unset")return null;oi.indexOf("javascript:")===0?(oi=oi.substr(11),si=!0):oi.indexOf("js:")===0&&(oi=oi.substr(3),si=!0),oi.indexOf("{")!==0&&(oi="{"+oi+"}");var ai;si?ai=Tr(ii,function(){return Function("return ("+oi+")")()},{}):ai=E(oi);for(var li in ai)ai.hasOwnProperty(li)&&ni[li]==null&&(ni[li]=ai[li])}return Rr(u(ii),ei,ti,ni)}function Tr(ii,ei,ti){return Q.config.allowEval?ei():(fe(ii,"htmx:evalDisallowedError"),ti)}function Or(ii,ei){return Rr(ii,"hx-vars",!0,ei)}function qr(ii,ei){return Rr(ii,"hx-vals",!1,ei)}function Hr(ii){return le(Or(ii),qr(ii))}function Lr(ii,ei,ti){if(ti!==null)try{ii.setRequestHeader(ei,ti)}catch(ni){ii.setRequestHeader(ei,encodeURIComponent(ti)),ii.setRequestHeader(ei+"-URI-AutoEncoded","true")}}function Ar(ii){if(ii.responseURL&&typeof URL!="undefined")try{var ei=new URL(ii.responseURL);return ei.pathname+ei.search}catch(ti){fe(re().body,"htmx:badResponseUrl",{url:ii.responseURL})}}function O(ii,ei){return ei.test(ii.getAllResponseHeaders())}function Nr(ii,ei,ti){return ii=ii.toLowerCase(),ti?ti instanceof Element||I(ti,"String")?he(ii,ei,null,null,{targetOverride:p(ti),returnPromise:!0}):he(ii,ei,p(ti.source),ti.event,{handler:ti.handler,headers:ti.headers,values:ti.values,targetOverride:p(ti.target),swapOverride:ti.swap,select:ti.select,returnPromise:!0}):he(ii,ei,null,null,{returnPromise:!0})}function Ir(ii){for(var ei=[];ii;)ei.push(ii),ii=ii.parentElement;return ei}function kr(ii,ei,ti){var ni,ri;if(typeof URL=="function"){ri=new URL(ei,document.location.href);var oi=document.location.origin;ni=oi===ri.origin}else ri=ei,ni=g(ei,document.location.origin);return Q.config.selfRequestsOnly&&!ni?!1:ce(ii,"htmx:validateUrl",le({url:ri,sameHost:ni},ti))}function he(ii,ei,ti,ni,ri,oi){var si=null,ai=null;if(ri=ri!=null?ri:{},ri.returnPromise&&typeof Promise!="undefined")var li=new Promise(function(On,zn){si=On,ai=zn});ti==null&&(ti=re().body);var ui=ri.handler||Mr,ci=ri.select||null;if(!se(ti))return ie(si),li;var di=ri.targetOverride||ye(ti);if(di==null||di==pe)return fe(ti,"htmx:targetError",{target:te(ti,"hx-target")}),ie(ai),li;var pi=ae(ti),yi=pi.lastButtonClicked;if(yi){var gi=ee(yi,"formaction");gi!=null&&(ei=gi);var vi=ee(yi,"formmethod");vi!=null&&vi.toLowerCase()!=="dialog"&&(ii=vi)}var Ei=ne(ti,"hx-confirm");if(oi===void 0){var Si=function(On){return he(ii,ei,ti,ni,ri,!!On)},xi={target:di,elt:ti,path:ei,verb:ii,triggeringEvent:ni,etc:ri,issueRequest:Si,question:Ei};if(ce(ti,"htmx:confirm",xi)===!1)return ie(si),li}var Li=ti,Oi=ne(ti,"hx-sync"),zi=null,Vi=!1;if(Oi){var ki=Oi.split(":"),Mi=ki[0].trim();if(Mi==="this"?Li=xe(ti,"hx-sync"):Li=ue(ti,Mi),Oi=(ki[1]||"drop").trim(),pi=ae(Li),Oi==="drop"&&pi.xhr&&pi.abortable!==!0)return ie(si),li;if(Oi==="abort"){if(pi.xhr)return ie(si),li;Vi=!0}else if(Oi==="replace")ce(Li,"htmx:abort");else if(Oi.indexOf("queue")===0){var Ai=Oi.split(" ");zi=(Ai[1]||"last").trim()}}if(pi.xhr)if(pi.abortable)ce(Li,"htmx:abort");else{if(zi==null){if(ni){var qi=ae(ni);qi&&qi.triggerSpec&&qi.triggerSpec.queue&&(zi=qi.triggerSpec.queue)}zi==null&&(zi="last")}return pi.queuedRequests==null&&(pi.queuedRequests=[]),zi==="first"&&pi.queuedRequests.length===0?pi.queuedRequests.push(function(){he(ii,ei,ti,ni,ri)}):zi==="all"?pi.queuedRequests.push(function(){he(ii,ei,ti,ni,ri)}):zi==="last"&&(pi.queuedRequests=[],pi.queuedRequests.push(function(){he(ii,ei,ti,ni,ri)})),ie(si),li}var Ci=new XMLHttpRequest;pi.xhr=Ci,pi.abortable=Vi;var Qi=function(){if(pi.xhr=null,pi.abortable=!1,pi.queuedRequests!=null&&pi.queuedRequests.length>0){var On=pi.queuedRequests.shift();On()}},Ji=ne(ti,"hx-prompt");if(Ji){var gn=prompt(Ji);if(gn===null||!ce(ti,"htmx:prompt",{prompt:gn,target:di}))return ie(si),Qi(),li}if(Ei&&!oi&&!confirm(Ei))return ie(si),Qi(),li;var rn=xr(ti,di,gn);ii!=="get"&&!Sr(ti)&&(rn["Content-Type"]="application/x-www-form-urlencoded"),ri.headers&&(rn=le(rn,ri.headers));var Zi=dr(ti,ii),on=Zi.errors,Mn=Zi.values;ri.values&&(Mn=le(Mn,ri.values));var vn=Hr(ti),Yi=le(Mn,vn),Ri=yr(Yi,ti);Q.config.getCacheBusterParam&&ii==="get"&&(Ri["org.htmx.cache-buster"]=ee(di,"id")||"true"),(ei==null||ei==="")&&(ei=re().location.href);var Ii=Rr(ti,"hx-request"),Ui=ae(ti).boosted,ji=Q.config.methodsThatUseUrlParams.indexOf(ii)>=0,Pi={boosted:Ui,useUrlParams:ji,parameters:Ri,unfilteredParameters:Yi,headers:rn,target:di,verb:ii,errors:on,withCredentials:ri.credentials||Ii.credentials||Q.config.withCredentials,timeout:ri.timeout||Ii.timeout||Q.config.timeout,path:ei,triggeringEvent:ni};if(!ce(ti,"htmx:configRequest",Pi))return ie(si),Qi(),li;if(ei=Pi.path,ii=Pi.verb,rn=Pi.headers,Ri=Pi.parameters,on=Pi.errors,ji=Pi.useUrlParams,on&&on.length>0)return ce(ti,"htmx:validation:halted",Pi),ie(si),Qi(),li;var ln=ei.split("#"),kn=ln[0],yn=ln[1],Sn=ei;if(ji){Sn=kn;var $s=Object.keys(Ri).length!==0;$s&&(Sn.indexOf("?")<0?Sn+="?":Sn+="&",Sn+=pr(Ri),yn&&(Sn+="#"+yn))}if(!kr(ti,Sn,Pi))return fe(ti,"htmx:invalidPath",Pi),ie(ai),li;if(Ci.open(ii.toUpperCase(),Sn,!0),Ci.overrideMimeType("text/html"),Ci.withCredentials=Pi.withCredentials,Ci.timeout=Pi.timeout,!Ii.noHeaders){for(var ro in rn)if(rn.hasOwnProperty(ro)){var wo=rn[ro];Lr(Ci,ro,wo)}}var bn={xhr:Ci,target:di,requestConfig:Pi,etc:ri,boosted:Ui,select:ci,pathInfo:{requestPath:ei,finalRequestPath:Sn,anchor:yn}};if(Ci.onload=function(){try{var On=Ir(ti);if(bn.pathInfo.responsePath=Ar(Ci),ui(ti,bn),lr(xo,ao),ce(ti,"htmx:afterRequest",bn),ce(ti,"htmx:afterOnLoad",bn),!se(ti)){for(var zn=null;On.length>0&&zn==null;){var Gn=On.shift();se(Gn)&&(zn=Gn)}zn&&(ce(zn,"htmx:afterRequest",bn),ce(zn,"htmx:afterOnLoad",bn))}ie(si),Qi()}catch(Jn){throw fe(ti,"htmx:onLoadError",le({error:Jn},bn)),Jn}},Ci.onerror=function(){lr(xo,ao),fe(ti,"htmx:afterRequest",bn),fe(ti,"htmx:sendError",bn),ie(ai),Qi()},Ci.onabort=function(){lr(xo,ao),fe(ti,"htmx:afterRequest",bn),fe(ti,"htmx:sendAbort",bn),ie(ai),Qi()},Ci.ontimeout=function(){lr(xo,ao),fe(ti,"htmx:afterRequest",bn),fe(ti,"htmx:timeout",bn),ie(ai),Qi()},!ce(ti,"htmx:beforeRequest",bn))return ie(si),Qi(),li;var xo=or(ti),ao=sr(ti);oe(["loadstart","loadend","progress","abort"],function(On){oe([Ci,Ci.upload],function(zn){zn.addEventListener(On,function(Gn){ce(ti,"htmx:xhr:"+On,{lengthComputable:Gn.lengthComputable,loaded:Gn.loaded,total:Gn.total})})})}),ce(ti,"htmx:beforeSend",bn);var ls=ji?null:Er(Ci,ti,Ri);return Ci.send(ls),li}function Pr(ii,ei){var ti=ei.xhr,ni=null,ri=null;if(O(ti,/HX-Push:/i)?(ni=ti.getResponseHeader("HX-Push"),ri="push"):O(ti,/HX-Push-Url:/i)?(ni=ti.getResponseHeader("HX-Push-Url"),ri="push"):O(ti,/HX-Replace-Url:/i)&&(ni=ti.getResponseHeader("HX-Replace-Url"),ri="replace"),ni)return ni==="false"?{}:{type:ri,path:ni};var oi=ei.pathInfo.finalRequestPath,si=ei.pathInfo.responsePath,ai=ne(ii,"hx-push-url"),li=ne(ii,"hx-replace-url"),ui=ae(ii).boosted,ci=null,di=null;return ai?(ci="push",di=ai):li?(ci="replace",di=li):ui&&(ci="push",di=si||oi),di?di==="false"?{}:(di==="true"&&(di=si||oi),ei.pathInfo.anchor&&di.indexOf("#")===-1&&(di=di+"#"+ei.pathInfo.anchor),{type:ci,path:di}):{}}function Mr(ii,ei){var ti=ei.xhr,ni=ei.target,ri=ei.etc,oi=ei.requestConfig,si=ei.select;if(ce(ii,"htmx:beforeOnLoad",ei)){if(O(ti,/HX-Trigger:/i)&&_e(ti,"HX-Trigger",ii),O(ti,/HX-Location:/i)){er();var ai=ti.getResponseHeader("HX-Location"),li;ai.indexOf("{")===0&&(li=E(ai),ai=li.path,delete li.path),Nr("GET",ai,li).then(function(){tr(ai)});return}var ui=O(ti,/HX-Refresh:/i)&&ti.getResponseHeader("HX-Refresh")==="true";if(O(ti,/HX-Redirect:/i)){location.href=ti.getResponseHeader("HX-Redirect"),ui&&location.reload();return}if(ui){location.reload();return}O(ti,/HX-Retarget:/i)&&(ti.getResponseHeader("HX-Retarget")==="this"?ei.target=ii:ei.target=ue(ii,ti.getResponseHeader("HX-Retarget")));var ci=Pr(ii,ei),di=ti.status>=200&&ti.status<400&&ti.status!==204,pi=ti.response,yi=ti.status>=400,gi=Q.config.ignoreTitle,vi=le({shouldSwap:di,serverResponse:pi,isError:yi,ignoreTitle:gi},ei);if(ce(ni,"htmx:beforeSwap",vi)){if(ni=vi.target,pi=vi.serverResponse,yi=vi.isError,gi=vi.ignoreTitle,ei.target=ni,ei.failed=yi,ei.successful=!yi,vi.shouldSwap){ti.status===286&&at(ii),R(ii,function(Mi){pi=Mi.transformResponse(pi,ti,ii)}),ci.type&&er();var Ei=ri.swapOverride;O(ti,/HX-Reswap:/i)&&(Ei=ti.getResponseHeader("HX-Reswap"));var li=wr(ii,Ei);li.hasOwnProperty("ignoreTitle")&&(gi=li.ignoreTitle),ni.classList.add(Q.config.swappingClass);var Si=null,xi=null,Li=function(){try{var Mi=document.activeElement,Ai={};try{Ai={elt:Mi,start:Mi?Mi.selectionStart:null,end:Mi?Mi.selectionEnd:null}}catch(Zi){}var qi;si&&(qi=si),O(ti,/HX-Reselect:/i)&&(qi=ti.getResponseHeader("HX-Reselect")),ci.type&&(ce(re().body,"htmx:beforeHistoryUpdate",le({history:ci},ei)),ci.type==="push"?(tr(ci.path),ce(re().body,"htmx:pushedIntoHistory",{path:ci.path})):(rr(ci.path),ce(re().body,"htmx:replacedInHistory",{path:ci.path})));var Ci=T(ni);if(je(li.swapStyle,ni,ii,pi,Ci,qi),Ai.elt&&!se(Ai.elt)&&ee(Ai.elt,"id")){var Qi=document.getElementById(ee(Ai.elt,"id")),Ji={preventScroll:li.focusScroll!==void 0?!li.focusScroll:!Q.config.defaultFocusScroll};if(Qi){if(Ai.start&&Qi.setSelectionRange)try{Qi.setSelectionRange(Ai.start,Ai.end)}catch(Zi){}Qi.focus(Ji)}}if(ni.classList.remove(Q.config.swappingClass),oe(Ci.elts,function(Zi){Zi.classList&&Zi.classList.add(Q.config.settlingClass),ce(Zi,"htmx:afterSwap",ei)}),O(ti,/HX-Trigger-After-Swap:/i)){var gn=ii;se(ii)||(gn=re().body),_e(ti,"HX-Trigger-After-Swap",gn)}var rn=function(){if(oe(Ci.tasks,function(vn){vn.call()}),oe(Ci.elts,function(vn){vn.classList&&vn.classList.remove(Q.config.settlingClass),ce(vn,"htmx:afterSettle",ei)}),ei.pathInfo.anchor){var Zi=re().getElementById(ei.pathInfo.anchor);Zi&&Zi.scrollIntoView({block:"start",behavior:"auto"})}if(Ci.title&&!gi){var on=C("title");on?on.innerHTML=Ci.title:window.document.title=Ci.title}if(Cr(Ci.elts,li),O(ti,/HX-Trigger-After-Settle:/i)){var Mn=ii;se(ii)||(Mn=re().body),_e(ti,"HX-Trigger-After-Settle",Mn)}ie(Si)};li.settleDelay>0?setTimeout(rn,li.settleDelay):rn()}catch(Zi){throw fe(ii,"htmx:swapError",ei),ie(xi),Zi}},Oi=Q.config.globalViewTransitions;if(li.hasOwnProperty("transition")&&(Oi=li.transition),Oi&&ce(ii,"htmx:beforeTransition",ei)&&typeof Promise!="undefined"&&document.startViewTransition){var zi=new Promise(function(Mi,Ai){Si=Mi,xi=Ai}),Vi=Li;Li=function(){document.startViewTransition(function(){return Vi(),zi})}}li.swapDelay>0?setTimeout(Li,li.swapDelay):Li()}yi&&fe(ii,"htmx:responseError",le({error:"Response Status Error Code "+ti.status+" from "+ei.pathInfo.requestPath},ei))}}}var Xr={};function Dr(){return{init:function(ii){return null},onEvent:function(ii,ei){return!0},transformResponse:function(ii,ei,ti){return ii},isInlineSwap:function(ii){return!1},handleSwap:function(ii,ei,ti,ni){return!1},encodeParameters:function(ii,ei,ti){return null}}}function Ur(ii,ei){ei.init&&ei.init(r),Xr[ii]=le(Dr(),ei)}function Br(ii){delete Xr[ii]}function Fr(ii,ei,ti){if(ii==null)return ei;ei==null&&(ei=[]),ti==null&&(ti=[]);var ni=te(ii,"hx-ext");return ni&&oe(ni.split(","),function(ri){if(ri=ri.replace(/ /g,""),ri.slice(0,7)=="ignore:"){ti.push(ri.slice(7));return}if(ti.indexOf(ri)<0){var oi=Xr[ri];oi&&ei.indexOf(oi)<0&&ei.push(oi)}}),Fr(u(ii),ei,ti)}var Vr=!1;re().addEventListener("DOMContentLoaded",function(){Vr=!0});function jr(ii){Vr||re().readyState==="complete"?ii():re().addEventListener("DOMContentLoaded",ii)}function _r(){Q.config.includeIndicatorStyles!==!1&&re().head.insertAdjacentHTML("beforeend","")}function zr(){var ii=re().querySelector('meta[name="htmx-config"]');return ii?E(ii.content):null}function $r(){var ii=zr();ii&&(Q.config=le(Q.config,ii))}return jr(function(){$r(),_r();var ii=re().body;zt(ii);var ei=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");ii.addEventListener("htmx:abort",function(ni){var ri=ni.target,oi=ae(ri);oi&&oi.xhr&&oi.xhr.abort()});let ti=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(ni){ni.state&&ni.state.htmx?(ar(),oe(ei,function(ri){ce(ri,"htmx:restored",{document:re(),triggerEvent:ce})})):ti&&ti(ni)},setTimeout(function(){ce(ii,"htmx:load",{}),ii=null},0)}),Q}()})});var fh=au((va,Uc)=>{(function(ei,ti){typeof va=="object"&&typeof Uc=="object"?Uc.exports=ti():typeof define=="function"&&define.amd?define([],ti):typeof va=="object"?va.ClipboardJS=ti():ei.ClipboardJS=ti()})(va,function(){return function(){var ii={686:function(ni,ri,oi){"use strict";oi.d(ri,{default:function(){return vn}});var si=oi(279),ai=oi.n(si),li=oi(370),ui=oi.n(li),ci=oi(817),di=oi.n(ci);function pi(Yi){try{return document.execCommand(Yi)}catch(Ri){return!1}}var yi=function(Ri){var Ii=di()(Ri);return pi("cut"),Ii},gi=yi;function vi(Yi){var Ri=document.documentElement.getAttribute("dir")==="rtl",Ii=document.createElement("textarea");Ii.style.fontSize="12pt",Ii.style.border="0",Ii.style.padding="0",Ii.style.margin="0",Ii.style.position="absolute",Ii.style[Ri?"right":"left"]="-9999px";var Ui=window.pageYOffset||document.documentElement.scrollTop;return Ii.style.top="".concat(Ui,"px"),Ii.setAttribute("readonly",""),Ii.value=Yi,Ii}var Ei=function(Ri,Ii){var Ui=vi(Ri);Ii.container.appendChild(Ui);var ji=di()(Ui);return pi("copy"),Ui.remove(),ji},Si=function(Ri){var Ii=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},Ui="";return typeof Ri=="string"?Ui=Ei(Ri,Ii):Ri instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(Ri==null?void 0:Ri.type)?Ui=Ei(Ri.value,Ii):(Ui=di()(Ri),pi("copy")),Ui},xi=Si;function Li(Yi){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Li=function(Ii){return typeof Ii}:Li=function(Ii){return Ii&&typeof Symbol=="function"&&Ii.constructor===Symbol&&Ii!==Symbol.prototype?"symbol":typeof Ii},Li(Yi)}var Oi=function(){var Ri=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},Ii=Ri.action,Ui=Ii===void 0?"copy":Ii,ji=Ri.container,Pi=Ri.target,ln=Ri.text;if(Ui!=="copy"&&Ui!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Pi!==void 0)if(Pi&&Li(Pi)==="object"&&Pi.nodeType===1){if(Ui==="copy"&&Pi.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(Ui==="cut"&&(Pi.hasAttribute("readonly")||Pi.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ln)return xi(ln,{container:ji});if(Pi)return Ui==="cut"?gi(Pi):xi(Pi,{container:ji})},zi=Oi;function Vi(Yi){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Vi=function(Ii){return typeof Ii}:Vi=function(Ii){return Ii&&typeof Symbol=="function"&&Ii.constructor===Symbol&&Ii!==Symbol.prototype?"symbol":typeof Ii},Vi(Yi)}function ki(Yi,Ri){if(!(Yi instanceof Ri))throw new TypeError("Cannot call a class as a function")}function Mi(Yi,Ri){for(var Ii=0;Ii0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof ji.action=="function"?ji.action:this.defaultAction,this.target=typeof ji.target=="function"?ji.target:this.defaultTarget,this.text=typeof ji.text=="function"?ji.text:this.defaultText,this.container=Vi(ji.container)==="object"?ji.container:document.body}},{key:"listenClick",value:function(ji){var Pi=this;this.listener=ui()(ji,"click",function(ln){return Pi.onClick(ln)})}},{key:"onClick",value:function(ji){var Pi=ji.delegateTarget||ji.currentTarget,ln=this.action(Pi)||"copy",kn=zi({action:ln,container:this.container,target:this.target(Pi),text:this.text(Pi)});this.emit(kn?"success":"error",{action:ln,text:kn,trigger:Pi,clearSelection:function(){Pi&&Pi.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(ji){return on("action",ji)}},{key:"defaultTarget",value:function(ji){var Pi=on("target",ji);if(Pi)return document.querySelector(Pi)}},{key:"defaultText",value:function(ji){return on("text",ji)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(ji){var Pi=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return xi(ji,Pi)}},{key:"cut",value:function(ji){return gi(ji)}},{key:"isSupported",value:function(){var ji=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Pi=typeof ji=="string"?[ji]:ji,ln=!!document.queryCommandSupported;return Pi.forEach(function(kn){ln=ln&&!!document.queryCommandSupported(kn)}),ln}}]),Ii}(ai()),vn=Mn},828:function(ni){var ri=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var oi=Element.prototype;oi.matches=oi.matchesSelector||oi.mozMatchesSelector||oi.msMatchesSelector||oi.oMatchesSelector||oi.webkitMatchesSelector}function si(ai,li){for(;ai&&ai.nodeType!==ri;){if(typeof ai.matches=="function"&&ai.matches(li))return ai;ai=ai.parentNode}}ni.exports=si},438:function(ni,ri,oi){var si=oi(828);function ai(ci,di,pi,yi,gi){var vi=ui.apply(this,arguments);return ci.addEventListener(pi,vi,gi),{destroy:function(){ci.removeEventListener(pi,vi,gi)}}}function li(ci,di,pi,yi,gi){return typeof ci.addEventListener=="function"?ai.apply(null,arguments):typeof pi=="function"?ai.bind(null,document).apply(null,arguments):(typeof ci=="string"&&(ci=document.querySelectorAll(ci)),Array.prototype.map.call(ci,function(vi){return ai(vi,di,pi,yi,gi)}))}function ui(ci,di,pi,yi){return function(gi){gi.delegateTarget=si(gi.target,di),gi.delegateTarget&&yi.call(ci,gi)}}ni.exports=li},879:function(ni,ri){ri.node=function(oi){return oi!==void 0&&oi instanceof HTMLElement&&oi.nodeType===1},ri.nodeList=function(oi){var si=Object.prototype.toString.call(oi);return oi!==void 0&&(si==="[object NodeList]"||si==="[object HTMLCollection]")&&"length"in oi&&(oi.length===0||ri.node(oi[0]))},ri.string=function(oi){return typeof oi=="string"||oi instanceof String},ri.fn=function(oi){var si=Object.prototype.toString.call(oi);return si==="[object Function]"}},370:function(ni,ri,oi){var si=oi(879),ai=oi(438);function li(pi,yi,gi){if(!pi&&!yi&&!gi)throw new Error("Missing required arguments");if(!si.string(yi))throw new TypeError("Second argument must be a String");if(!si.fn(gi))throw new TypeError("Third argument must be a Function");if(si.node(pi))return ui(pi,yi,gi);if(si.nodeList(pi))return ci(pi,yi,gi);if(si.string(pi))return di(pi,yi,gi);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function ui(pi,yi,gi){return pi.addEventListener(yi,gi),{destroy:function(){pi.removeEventListener(yi,gi)}}}function ci(pi,yi,gi){return Array.prototype.forEach.call(pi,function(vi){vi.addEventListener(yi,gi)}),{destroy:function(){Array.prototype.forEach.call(pi,function(vi){vi.removeEventListener(yi,gi)})}}}function di(pi,yi,gi){return ai(document.body,pi,yi,gi)}ni.exports=li},817:function(ni){function ri(oi){var si;if(oi.nodeName==="SELECT")oi.focus(),si=oi.value;else if(oi.nodeName==="INPUT"||oi.nodeName==="TEXTAREA"){var ai=oi.hasAttribute("readonly");ai||oi.setAttribute("readonly",""),oi.select(),oi.setSelectionRange(0,oi.value.length),ai||oi.removeAttribute("readonly"),si=oi.value}else{oi.hasAttribute("contenteditable")&&oi.focus();var li=window.getSelection(),ui=document.createRange();ui.selectNodeContents(oi),li.removeAllRanges(),li.addRange(ui),si=li.toString()}return si}ni.exports=ri},279:function(ni){function ri(){}ri.prototype={on:function(oi,si,ai){var li=this.e||(this.e={});return(li[oi]||(li[oi]=[])).push({fn:si,ctx:ai}),this},once:function(oi,si,ai){var li=this;function ui(){li.off(oi,ui),si.apply(ai,arguments)}return ui._=si,this.on(oi,ui,ai)},emit:function(oi){var si=[].slice.call(arguments,1),ai=((this.e||(this.e={}))[oi]||[]).slice(),li=0,ui=ai.length;for(li;limu,afterRead:()=>fu,afterWrite:()=>yu,applyStyles:()=>ps,arrow:()=>Oa,auto:()=>js,basePlacements:()=>uo,beforeMain:()=>hu,beforeRead:()=>uu,beforeWrite:()=>gu,bottom:()=>_n,clippingParents:()=>$l,computeStyles:()=>gs,createPopper:()=>Js,createPopperBase:()=>Au,createPopperLite:()=>Du,detectOverflow:()=>Fn,end:()=>To,eventListeners:()=>vs,flip:()=>Na,hide:()=>Ra,left:()=>hn,main:()=>pu,modifierPhases:()=>zl,offset:()=>Ia,placements:()=>Ws,popper:()=>jo,popperGenerator:()=>Xo,popperOffsets:()=>_s,preventOverflow:()=>Ha,read:()=>du,reference:()=>Bl,right:()=>mn,start:()=>so,top:()=>dn,variationPlacements:()=>Da,viewport:()=>qs,write:()=>vu});var dn="top",_n="bottom",mn="right",hn="left",js="auto",uo=[dn,_n,mn,hn],so="start",To="end",$l="clippingParents",qs="viewport",jo="popper",Bl="reference",Da=uo.reduce(function(ii,ei){return ii.concat([ei+"-"+so,ei+"-"+To])},[]),Ws=[].concat(uo,[js]).reduce(function(ii,ei){return ii.concat([ei,ei+"-"+so,ei+"-"+To])},[]),uu="beforeRead",du="read",fu="afterRead",hu="beforeMain",pu="main",mu="afterMain",gu="beforeWrite",vu="write",yu="afterWrite",zl=[uu,du,fu,hu,pu,mu,gu,vu,yu];function An(ii){return ii?(ii.nodeName||"").toLowerCase():null}function cn(ii){if(ii==null)return window;if(ii.toString()!=="[object Window]"){var ei=ii.ownerDocument;return ei&&ei.defaultView||window}return ii}function Zn(ii){var ei=cn(ii).Element;return ii instanceof ei||ii instanceof Element}function Tn(ii){var ei=cn(ii).HTMLElement;return ii instanceof ei||ii instanceof HTMLElement}function hs(ii){if(typeof ShadowRoot=="undefined")return!1;var ei=cn(ii).ShadowRoot;return ii instanceof ei||ii instanceof ShadowRoot}function op(ii){var ei=ii.state;Object.keys(ei.elements).forEach(function(ti){var ni=ei.styles[ti]||{},ri=ei.attributes[ti]||{},oi=ei.elements[ti];!Tn(oi)||!An(oi)||(Object.assign(oi.style,ni),Object.keys(ri).forEach(function(si){var ai=ri[si];ai===!1?oi.removeAttribute(si):oi.setAttribute(si,ai===!0?"":ai)}))})}function sp(ii){var ei=ii.state,ti={popper:{position:ei.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(ei.elements.popper.style,ti.popper),ei.styles=ti,ei.elements.arrow&&Object.assign(ei.elements.arrow.style,ti.arrow),function(){Object.keys(ei.elements).forEach(function(ni){var ri=ei.elements[ni],oi=ei.attributes[ni]||{},si=Object.keys(ei.styles.hasOwnProperty(ni)?ei.styles[ni]:ti[ni]),ai=si.reduce(function(li,ui){return li[ui]="",li},{});!Tn(ri)||!An(ri)||(Object.assign(ri.style,ai),Object.keys(oi).forEach(function(li){ri.removeAttribute(li)}))})}}var ps={name:"applyStyles",enabled:!0,phase:"write",fn:op,effect:sp,requires:["computeStyles"]};function Dn(ii){return ii.split("-")[0]}var eo=Math.max,qo=Math.min,fo=Math.round;function ms(){var ii=navigator.userAgentData;return ii!=null&&ii.brands&&Array.isArray(ii.brands)?ii.brands.map(function(ei){return ei.brand+"/"+ei.version}).join(" "):navigator.userAgent}function Us(){return!/^((?!chrome|android).)*safari/i.test(ms())}function Wr(ii,ei,ti){ei===void 0&&(ei=!1),ti===void 0&&(ti=!1);var ni=ii.getBoundingClientRect(),ri=1,oi=1;ei&&Tn(ii)&&(ri=ii.offsetWidth>0&&fo(ni.width)/ii.offsetWidth||1,oi=ii.offsetHeight>0&&fo(ni.height)/ii.offsetHeight||1);var si=Zn(ii)?cn(ii):window,ai=si.visualViewport,li=!Us()&&ti,ui=(ni.left+(li&&ai?ai.offsetLeft:0))/ri,ci=(ni.top+(li&&ai?ai.offsetTop:0))/oi,di=ni.width/ri,pi=ni.height/oi;return{width:di,height:pi,top:ci,right:ui+di,bottom:ci+pi,left:ui,x:ui,y:ci}}function Wo(ii){var ei=Wr(ii),ti=ii.offsetWidth,ni=ii.offsetHeight;return Math.abs(ei.width-ti)<=1&&(ti=ei.width),Math.abs(ei.height-ni)<=1&&(ni=ei.height),{x:ii.offsetLeft,y:ii.offsetTop,width:ti,height:ni}}function Ys(ii,ei){var ti=ei.getRootNode&&ei.getRootNode();if(ii.contains(ei))return!0;if(ti&&hs(ti)){var ni=ei;do{if(ni&&ii.isSameNode(ni))return!0;ni=ni.parentNode||ni.host}while(ni)}return!1}function Pn(ii){return cn(ii).getComputedStyle(ii)}function Vl(ii){return["table","td","th"].indexOf(An(ii))>=0}function Ln(ii){return((Zn(ii)?ii.ownerDocument:ii.document)||window.document).documentElement}function ho(ii){return An(ii)==="html"?ii:ii.assignedSlot||ii.parentNode||(hs(ii)?ii.host:null)||Ln(ii)}function bu(ii){return!Tn(ii)||Pn(ii).position==="fixed"?null:ii.offsetParent}function ap(ii){var ei=/firefox/i.test(ms()),ti=/Trident/i.test(ms());if(ti&&Tn(ii)){var ni=Pn(ii);if(ni.position==="fixed")return null}var ri=ho(ii);for(hs(ri)&&(ri=ri.host);Tn(ri)&&["html","body"].indexOf(An(ri))<0;){var oi=Pn(ri);if(oi.transform!=="none"||oi.perspective!=="none"||oi.contain==="paint"||["transform","perspective"].indexOf(oi.willChange)!==-1||ei&&oi.willChange==="filter"||ei&&oi.filter&&oi.filter!=="none")return ri;ri=ri.parentNode}return null}function to(ii){for(var ei=cn(ii),ti=bu(ii);ti&&Vl(ti)&&Pn(ti).position==="static";)ti=bu(ti);return ti&&(An(ti)==="html"||An(ti)==="body"&&Pn(ti).position==="static")?ei:ti||ap(ii)||ei}function Uo(ii){return["top","bottom"].indexOf(ii)>=0?"x":"y"}function Yo(ii,ei,ti){return eo(ii,qo(ei,ti))}function _u(ii,ei,ti){var ni=Yo(ii,ei,ti);return ni>ti?ti:ni}function Gs(){return{top:0,right:0,bottom:0,left:0}}function Ks(ii){return Object.assign({},Gs(),ii)}function Qs(ii,ei){return ei.reduce(function(ti,ni){return ti[ni]=ii,ti},{})}var lp=function(ei,ti){return ei=typeof ei=="function"?ei(Object.assign({},ti.rects,{placement:ti.placement})):ei,Ks(typeof ei!="number"?ei:Qs(ei,uo))};function cp(ii){var ei,ti=ii.state,ni=ii.name,ri=ii.options,oi=ti.elements.arrow,si=ti.modifiersData.popperOffsets,ai=Dn(ti.placement),li=Uo(ai),ui=[hn,mn].indexOf(ai)>=0,ci=ui?"height":"width";if(!(!oi||!si)){var di=lp(ri.padding,ti),pi=Wo(oi),yi=li==="y"?dn:hn,gi=li==="y"?_n:mn,vi=ti.rects.reference[ci]+ti.rects.reference[li]-si[li]-ti.rects.popper[ci],Ei=si[li]-ti.rects.reference[li],Si=to(oi),xi=Si?li==="y"?Si.clientHeight||0:Si.clientWidth||0:0,Li=vi/2-Ei/2,Oi=di[yi],zi=xi-pi[ci]-di[gi],Vi=xi/2-pi[ci]/2+Li,ki=Yo(Oi,Vi,zi),Mi=li;ti.modifiersData[ni]=(ei={},ei[Mi]=ki,ei.centerOffset=ki-Vi,ei)}}function up(ii){var ei=ii.state,ti=ii.options,ni=ti.element,ri=ni===void 0?"[data-popper-arrow]":ni;ri!=null&&(typeof ri=="string"&&(ri=ei.elements.popper.querySelector(ri),!ri)||Ys(ei.elements.popper,ri)&&(ei.elements.arrow=ri))}var Oa={name:"arrow",enabled:!0,phase:"main",fn:cp,effect:up,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Yr(ii){return ii.split("-")[1]}var dp={top:"auto",right:"auto",bottom:"auto",left:"auto"};function fp(ii,ei){var ti=ii.x,ni=ii.y,ri=ei.devicePixelRatio||1;return{x:fo(ti*ri)/ri||0,y:fo(ni*ri)/ri||0}}function Eu(ii){var ei,ti=ii.popper,ni=ii.popperRect,ri=ii.placement,oi=ii.variation,si=ii.offsets,ai=ii.position,li=ii.gpuAcceleration,ui=ii.adaptive,ci=ii.roundOffsets,di=ii.isFixed,pi=si.x,yi=pi===void 0?0:pi,gi=si.y,vi=gi===void 0?0:gi,Ei=typeof ci=="function"?ci({x:yi,y:vi}):{x:yi,y:vi};yi=Ei.x,vi=Ei.y;var Si=si.hasOwnProperty("x"),xi=si.hasOwnProperty("y"),Li=hn,Oi=dn,zi=window;if(ui){var Vi=to(ti),ki="clientHeight",Mi="clientWidth";if(Vi===cn(ti)&&(Vi=Ln(ti),Pn(Vi).position!=="static"&&ai==="absolute"&&(ki="scrollHeight",Mi="scrollWidth")),Vi=Vi,ri===dn||(ri===hn||ri===mn)&&oi===To){Oi=_n;var Ai=di&&Vi===zi&&zi.visualViewport?zi.visualViewport.height:Vi[ki];vi-=Ai-ni.height,vi*=li?1:-1}if(ri===hn||(ri===dn||ri===_n)&&oi===To){Li=mn;var qi=di&&Vi===zi&&zi.visualViewport?zi.visualViewport.width:Vi[Mi];yi-=qi-ni.width,yi*=li?1:-1}}var Ci=Object.assign({position:ai},ui&&dp),Qi=ci===!0?fp({x:yi,y:vi},cn(ti)):{x:yi,y:vi};if(yi=Qi.x,vi=Qi.y,li){var Ji;return Object.assign({},Ci,(Ji={},Ji[Oi]=xi?"0":"",Ji[Li]=Si?"0":"",Ji.transform=(zi.devicePixelRatio||1)<=1?"translate("+yi+"px, "+vi+"px)":"translate3d("+yi+"px, "+vi+"px, 0)",Ji))}return Object.assign({},Ci,(ei={},ei[Oi]=xi?vi+"px":"",ei[Li]=Si?yi+"px":"",ei.transform="",ei))}function hp(ii){var ei=ii.state,ti=ii.options,ni=ti.gpuAcceleration,ri=ni===void 0?!0:ni,oi=ti.adaptive,si=oi===void 0?!0:oi,ai=ti.roundOffsets,li=ai===void 0?!0:ai,ui={placement:Dn(ei.placement),variation:Yr(ei.placement),popper:ei.elements.popper,popperRect:ei.rects.popper,gpuAcceleration:ri,isFixed:ei.options.strategy==="fixed"};ei.modifiersData.popperOffsets!=null&&(ei.styles.popper=Object.assign({},ei.styles.popper,Eu(Object.assign({},ui,{offsets:ei.modifiersData.popperOffsets,position:ei.options.strategy,adaptive:si,roundOffsets:li})))),ei.modifiersData.arrow!=null&&(ei.styles.arrow=Object.assign({},ei.styles.arrow,Eu(Object.assign({},ui,{offsets:ei.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:li})))),ei.attributes.popper=Object.assign({},ei.attributes.popper,{"data-popper-placement":ei.placement})}var gs={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:hp,data:{}};var La={passive:!0};function pp(ii){var ei=ii.state,ti=ii.instance,ni=ii.options,ri=ni.scroll,oi=ri===void 0?!0:ri,si=ni.resize,ai=si===void 0?!0:si,li=cn(ei.elements.popper),ui=[].concat(ei.scrollParents.reference,ei.scrollParents.popper);return oi&&ui.forEach(function(ci){ci.addEventListener("scroll",ti.update,La)}),ai&&li.addEventListener("resize",ti.update,La),function(){oi&&ui.forEach(function(ci){ci.removeEventListener("scroll",ti.update,La)}),ai&&li.removeEventListener("resize",ti.update,La)}}var vs={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:pp,data:{}};var mp={left:"right",right:"left",bottom:"top",top:"bottom"};function ys(ii){return ii.replace(/left|right|bottom|top/g,function(ei){return mp[ei]})}var gp={start:"end",end:"start"};function Ma(ii){return ii.replace(/start|end/g,function(ei){return gp[ei]})}function Go(ii){var ei=cn(ii),ti=ei.pageXOffset,ni=ei.pageYOffset;return{scrollLeft:ti,scrollTop:ni}}function Ko(ii){return Wr(Ln(ii)).left+Go(ii).scrollLeft}function jl(ii,ei){var ti=cn(ii),ni=Ln(ii),ri=ti.visualViewport,oi=ni.clientWidth,si=ni.clientHeight,ai=0,li=0;if(ri){oi=ri.width,si=ri.height;var ui=Us();(ui||!ui&&ei==="fixed")&&(ai=ri.offsetLeft,li=ri.offsetTop)}return{width:oi,height:si,x:ai+Ko(ii),y:li}}function ql(ii){var ei,ti=Ln(ii),ni=Go(ii),ri=(ei=ii.ownerDocument)==null?void 0:ei.body,oi=eo(ti.scrollWidth,ti.clientWidth,ri?ri.scrollWidth:0,ri?ri.clientWidth:0),si=eo(ti.scrollHeight,ti.clientHeight,ri?ri.scrollHeight:0,ri?ri.clientHeight:0),ai=-ni.scrollLeft+Ko(ii),li=-ni.scrollTop;return Pn(ri||ti).direction==="rtl"&&(ai+=eo(ti.clientWidth,ri?ri.clientWidth:0)-oi),{width:oi,height:si,x:ai,y:li}}function Qo(ii){var ei=Pn(ii),ti=ei.overflow,ni=ei.overflowX,ri=ei.overflowY;return/auto|scroll|overlay|hidden/.test(ti+ri+ni)}function ka(ii){return["html","body","#document"].indexOf(An(ii))>=0?ii.ownerDocument.body:Tn(ii)&&Qo(ii)?ii:ka(ho(ii))}function Co(ii,ei){var ti;ei===void 0&&(ei=[]);var ni=ka(ii),ri=ni===((ti=ii.ownerDocument)==null?void 0:ti.body),oi=cn(ni),si=ri?[oi].concat(oi.visualViewport||[],Qo(ni)?ni:[]):ni,ai=ei.concat(si);return ri?ai:ai.concat(Co(ho(si)))}function bs(ii){return Object.assign({},ii,{left:ii.x,top:ii.y,right:ii.x+ii.width,bottom:ii.y+ii.height})}function vp(ii,ei){var ti=Wr(ii,!1,ei==="fixed");return ti.top=ti.top+ii.clientTop,ti.left=ti.left+ii.clientLeft,ti.bottom=ti.top+ii.clientHeight,ti.right=ti.left+ii.clientWidth,ti.width=ii.clientWidth,ti.height=ii.clientHeight,ti.x=ti.left,ti.y=ti.top,ti}function wu(ii,ei,ti){return ei===qs?bs(jl(ii,ti)):Zn(ei)?vp(ei,ti):bs(ql(Ln(ii)))}function yp(ii){var ei=Co(ho(ii)),ti=["absolute","fixed"].indexOf(Pn(ii).position)>=0,ni=ti&&Tn(ii)?to(ii):ii;return Zn(ni)?ei.filter(function(ri){return Zn(ri)&&Ys(ri,ni)&&An(ri)!=="body"}):[]}function Wl(ii,ei,ti,ni){var ri=ei==="clippingParents"?yp(ii):[].concat(ei),oi=[].concat(ri,[ti]),si=oi[0],ai=oi.reduce(function(li,ui){var ci=wu(ii,ui,ni);return li.top=eo(ci.top,li.top),li.right=qo(ci.right,li.right),li.bottom=qo(ci.bottom,li.bottom),li.left=eo(ci.left,li.left),li},wu(ii,si,ni));return ai.width=ai.right-ai.left,ai.height=ai.bottom-ai.top,ai.x=ai.left,ai.y=ai.top,ai}function Xs(ii){var ei=ii.reference,ti=ii.element,ni=ii.placement,ri=ni?Dn(ni):null,oi=ni?Yr(ni):null,si=ei.x+ei.width/2-ti.width/2,ai=ei.y+ei.height/2-ti.height/2,li;switch(ri){case dn:li={x:si,y:ei.y-ti.height};break;case _n:li={x:si,y:ei.y+ei.height};break;case mn:li={x:ei.x+ei.width,y:ai};break;case hn:li={x:ei.x-ti.width,y:ai};break;default:li={x:ei.x,y:ei.y}}var ui=ri?Uo(ri):null;if(ui!=null){var ci=ui==="y"?"height":"width";switch(oi){case so:li[ui]=li[ui]-(ei[ci]/2-ti[ci]/2);break;case To:li[ui]=li[ui]+(ei[ci]/2-ti[ci]/2);break;default:}}return li}function Fn(ii,ei){ei===void 0&&(ei={});var ti=ei,ni=ti.placement,ri=ni===void 0?ii.placement:ni,oi=ti.strategy,si=oi===void 0?ii.strategy:oi,ai=ti.boundary,li=ai===void 0?$l:ai,ui=ti.rootBoundary,ci=ui===void 0?qs:ui,di=ti.elementContext,pi=di===void 0?jo:di,yi=ti.altBoundary,gi=yi===void 0?!1:yi,vi=ti.padding,Ei=vi===void 0?0:vi,Si=Ks(typeof Ei!="number"?Ei:Qs(Ei,uo)),xi=pi===jo?Bl:jo,Li=ii.rects.popper,Oi=ii.elements[gi?xi:pi],zi=Wl(Zn(Oi)?Oi:Oi.contextElement||Ln(ii.elements.popper),li,ci,si),Vi=Wr(ii.elements.reference),ki=Xs({reference:Vi,element:Li,strategy:"absolute",placement:ri}),Mi=bs(Object.assign({},Li,ki)),Ai=pi===jo?Mi:Vi,qi={top:zi.top-Ai.top+Si.top,bottom:Ai.bottom-zi.bottom+Si.bottom,left:zi.left-Ai.left+Si.left,right:Ai.right-zi.right+Si.right},Ci=ii.modifiersData.offset;if(pi===jo&&Ci){var Qi=Ci[ri];Object.keys(qi).forEach(function(Ji){var gn=[mn,_n].indexOf(Ji)>=0?1:-1,rn=[dn,_n].indexOf(Ji)>=0?"y":"x";qi[Ji]+=Qi[rn]*gn})}return qi}function Ul(ii,ei){ei===void 0&&(ei={});var ti=ei,ni=ti.placement,ri=ti.boundary,oi=ti.rootBoundary,si=ti.padding,ai=ti.flipVariations,li=ti.allowedAutoPlacements,ui=li===void 0?Ws:li,ci=Yr(ni),di=ci?ai?Da:Da.filter(function(gi){return Yr(gi)===ci}):uo,pi=di.filter(function(gi){return ui.indexOf(gi)>=0});pi.length===0&&(pi=di);var yi=pi.reduce(function(gi,vi){return gi[vi]=Fn(ii,{placement:vi,boundary:ri,rootBoundary:oi,padding:si})[Dn(vi)],gi},{});return Object.keys(yi).sort(function(gi,vi){return yi[gi]-yi[vi]})}function bp(ii){if(Dn(ii)===js)return[];var ei=ys(ii);return[Ma(ii),ei,Ma(ei)]}function _p(ii){var ei=ii.state,ti=ii.options,ni=ii.name;if(!ei.modifiersData[ni]._skip){for(var ri=ti.mainAxis,oi=ri===void 0?!0:ri,si=ti.altAxis,ai=si===void 0?!0:si,li=ti.fallbackPlacements,ui=ti.padding,ci=ti.boundary,di=ti.rootBoundary,pi=ti.altBoundary,yi=ti.flipVariations,gi=yi===void 0?!0:yi,vi=ti.allowedAutoPlacements,Ei=ei.options.placement,Si=Dn(Ei),xi=Si===Ei,Li=li||(xi||!gi?[ys(Ei)]:bp(Ei)),Oi=[Ei].concat(Li).reduce(function(ji,Pi){return ji.concat(Dn(Pi)===js?Ul(ei,{placement:Pi,boundary:ci,rootBoundary:di,padding:ui,flipVariations:gi,allowedAutoPlacements:vi}):Pi)},[]),zi=ei.rects.reference,Vi=ei.rects.popper,ki=new Map,Mi=!0,Ai=Oi[0],qi=0;qi=0,rn=gn?"width":"height",Zi=Fn(ei,{placement:Ci,boundary:ci,rootBoundary:di,altBoundary:pi,padding:ui}),on=gn?Ji?mn:hn:Ji?_n:dn;zi[rn]>Vi[rn]&&(on=ys(on));var Mn=ys(on),vn=[];if(oi&&vn.push(Zi[Qi]<=0),ai&&vn.push(Zi[on]<=0,Zi[Mn]<=0),vn.every(function(ji){return ji})){Ai=Ci,Mi=!1;break}ki.set(Ci,vn)}if(Mi)for(var Yi=gi?3:1,Ri=function(Pi){var ln=Oi.find(function(kn){var yn=ki.get(kn);if(yn)return yn.slice(0,Pi).every(function(Sn){return Sn})});if(ln)return Ai=ln,"break"},Ii=Yi;Ii>0;Ii--){var Ui=Ri(Ii);if(Ui==="break")break}ei.placement!==Ai&&(ei.modifiersData[ni]._skip=!0,ei.placement=Ai,ei.reset=!0)}}var Na={name:"flip",enabled:!0,phase:"main",fn:_p,requiresIfExists:["offset"],data:{_skip:!1}};function xu(ii,ei,ti){return ti===void 0&&(ti={x:0,y:0}),{top:ii.top-ei.height-ti.y,right:ii.right-ei.width+ti.x,bottom:ii.bottom-ei.height+ti.y,left:ii.left-ei.width-ti.x}}function Tu(ii){return[dn,mn,_n,hn].some(function(ei){return ii[ei]>=0})}function Ep(ii){var ei=ii.state,ti=ii.name,ni=ei.rects.reference,ri=ei.rects.popper,oi=ei.modifiersData.preventOverflow,si=Fn(ei,{elementContext:"reference"}),ai=Fn(ei,{altBoundary:!0}),li=xu(si,ni),ui=xu(ai,ri,oi),ci=Tu(li),di=Tu(ui);ei.modifiersData[ti]={referenceClippingOffsets:li,popperEscapeOffsets:ui,isReferenceHidden:ci,hasPopperEscaped:di},ei.attributes.popper=Object.assign({},ei.attributes.popper,{"data-popper-reference-hidden":ci,"data-popper-escaped":di})}var Ra={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:Ep};function wp(ii,ei,ti){var ni=Dn(ii),ri=[hn,dn].indexOf(ni)>=0?-1:1,oi=typeof ti=="function"?ti(Object.assign({},ei,{placement:ii})):ti,si=oi[0],ai=oi[1];return si=si||0,ai=(ai||0)*ri,[hn,mn].indexOf(ni)>=0?{x:ai,y:si}:{x:si,y:ai}}function xp(ii){var ei=ii.state,ti=ii.options,ni=ii.name,ri=ti.offset,oi=ri===void 0?[0,0]:ri,si=Ws.reduce(function(ci,di){return ci[di]=wp(di,ei.rects,oi),ci},{}),ai=si[ei.placement],li=ai.x,ui=ai.y;ei.modifiersData.popperOffsets!=null&&(ei.modifiersData.popperOffsets.x+=li,ei.modifiersData.popperOffsets.y+=ui),ei.modifiersData[ni]=si}var Ia={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:xp};function Tp(ii){var ei=ii.state,ti=ii.name;ei.modifiersData[ti]=Xs({reference:ei.rects.reference,element:ei.rects.popper,strategy:"absolute",placement:ei.placement})}var _s={name:"popperOffsets",enabled:!0,phase:"read",fn:Tp,data:{}};function Yl(ii){return ii==="x"?"y":"x"}function Cp(ii){var ei=ii.state,ti=ii.options,ni=ii.name,ri=ti.mainAxis,oi=ri===void 0?!0:ri,si=ti.altAxis,ai=si===void 0?!1:si,li=ti.boundary,ui=ti.rootBoundary,ci=ti.altBoundary,di=ti.padding,pi=ti.tether,yi=pi===void 0?!0:pi,gi=ti.tetherOffset,vi=gi===void 0?0:gi,Ei=Fn(ei,{boundary:li,rootBoundary:ui,padding:di,altBoundary:ci}),Si=Dn(ei.placement),xi=Yr(ei.placement),Li=!xi,Oi=Uo(Si),zi=Yl(Oi),Vi=ei.modifiersData.popperOffsets,ki=ei.rects.reference,Mi=ei.rects.popper,Ai=typeof vi=="function"?vi(Object.assign({},ei.rects,{placement:ei.placement})):vi,qi=typeof Ai=="number"?{mainAxis:Ai,altAxis:Ai}:Object.assign({mainAxis:0,altAxis:0},Ai),Ci=ei.modifiersData.offset?ei.modifiersData.offset[ei.placement]:null,Qi={x:0,y:0};if(Vi){if(oi){var Ji,gn=Oi==="y"?dn:hn,rn=Oi==="y"?_n:mn,Zi=Oi==="y"?"height":"width",on=Vi[Oi],Mn=on+Ei[gn],vn=on-Ei[rn],Yi=yi?-Mi[Zi]/2:0,Ri=xi===so?ki[Zi]:Mi[Zi],Ii=xi===so?-Mi[Zi]:-ki[Zi],Ui=ei.elements.arrow,ji=yi&&Ui?Wo(Ui):{width:0,height:0},Pi=ei.modifiersData["arrow#persistent"]?ei.modifiersData["arrow#persistent"].padding:Gs(),ln=Pi[gn],kn=Pi[rn],yn=Yo(0,ki[Zi],ji[Zi]),Sn=Li?ki[Zi]/2-Yi-yn-ln-qi.mainAxis:Ri-yn-ln-qi.mainAxis,$s=Li?-ki[Zi]/2+Yi+yn+kn+qi.mainAxis:Ii+yn+kn+qi.mainAxis,ro=ei.elements.arrow&&to(ei.elements.arrow),wo=ro?Oi==="y"?ro.clientTop||0:ro.clientLeft||0:0,bn=(Ji=Ci==null?void 0:Ci[Oi])!=null?Ji:0,xo=on+Sn-bn-wo,ao=on+$s-bn,ls=Yo(yi?qo(Mn,xo):Mn,on,yi?eo(vn,ao):vn);Vi[Oi]=ls,Qi[Oi]=ls-on}if(ai){var On,zn=Oi==="x"?dn:hn,Gn=Oi==="x"?_n:mn,Jn=Vi[zi],cs=zi==="y"?"height":"width",Bs=Jn+Ei[zn],us=Jn-Ei[Gn],ds=[dn,hn].indexOf(Si)!==-1,Vo=(On=Ci==null?void 0:Ci[zi])!=null?On:0,Ta=ds?Bs:Jn-ki[cs]-Mi[cs]-Vo+qi.altAxis,zs=ds?Jn+ki[cs]+Mi[cs]-Vo-qi.altAxis:us,Ca=yi&&ds?_u(Ta,Jn,zs):Yo(yi?Ta:Bs,Jn,yi?zs:us);Vi[zi]=Ca,Qi[zi]=Ca-Jn}ei.modifiersData[ni]=Qi}}var Ha={name:"preventOverflow",enabled:!0,phase:"main",fn:Cp,requiresIfExists:["offset"]};function Gl(ii){return{scrollLeft:ii.scrollLeft,scrollTop:ii.scrollTop}}function Kl(ii){return ii===cn(ii)||!Tn(ii)?Go(ii):Gl(ii)}function Sp(ii){var ei=ii.getBoundingClientRect(),ti=fo(ei.width)/ii.offsetWidth||1,ni=fo(ei.height)/ii.offsetHeight||1;return ti!==1||ni!==1}function Ql(ii,ei,ti){ti===void 0&&(ti=!1);var ni=Tn(ei),ri=Tn(ei)&&Sp(ei),oi=Ln(ei),si=Wr(ii,ri,ti),ai={scrollLeft:0,scrollTop:0},li={x:0,y:0};return(ni||!ni&&!ti)&&((An(ei)!=="body"||Qo(oi))&&(ai=Kl(ei)),Tn(ei)?(li=Wr(ei,!0),li.x+=ei.clientLeft,li.y+=ei.clientTop):oi&&(li.x=Ko(oi))),{x:si.left+ai.scrollLeft-li.x,y:si.top+ai.scrollTop-li.y,width:si.width,height:si.height}}function Ap(ii){var ei=new Map,ti=new Set,ni=[];ii.forEach(function(oi){ei.set(oi.name,oi)});function ri(oi){ti.add(oi.name);var si=[].concat(oi.requires||[],oi.requiresIfExists||[]);si.forEach(function(ai){if(!ti.has(ai)){var li=ei.get(ai);li&&ri(li)}}),ni.push(oi)}return ii.forEach(function(oi){ti.has(oi.name)||ri(oi)}),ni}function Xl(ii){var ei=Ap(ii);return zl.reduce(function(ti,ni){return ti.concat(ei.filter(function(ri){return ri.phase===ni}))},[])}function Jl(ii){var ei;return function(){return ei||(ei=new Promise(function(ti){Promise.resolve().then(function(){ei=void 0,ti(ii())})})),ei}}function Zl(ii){var ei=ii.reduce(function(ti,ni){var ri=ti[ni.name];return ti[ni.name]=ri?Object.assign({},ri,ni,{options:Object.assign({},ri.options,ni.options),data:Object.assign({},ri.data,ni.data)}):ni,ti},{});return Object.keys(ei).map(function(ti){return ei[ti]})}var Cu={placement:"bottom",modifiers:[],strategy:"absolute"};function Su(){for(var ii=arguments.length,ei=new Array(ii),ti=0;ti(ii&&window.CSS&&window.CSS.escape&&(ii=ii.replace(/#([^\s"#']+)/g,(ei,ti)=>`#${CSS.escape(ti)}`)),ii),kp=ii=>ii==null?`${ii}`:Object.prototype.toString.call(ii).match(/\s([a-z]+)/i)[1].toLowerCase(),Np=ii=>{do ii+=Math.floor(Math.random()*Lp);while(document.getElementById(ii));return ii},Rp=ii=>{if(!ii)return 0;let{transitionDuration:ei,transitionDelay:ti}=window.getComputedStyle(ii),ni=Number.parseFloat(ei),ri=Number.parseFloat(ti);return!ni&&!ri?0:(ei=ei.split(",")[0],ti=ti.split(",")[0],(Number.parseFloat(ei)+Number.parseFloat(ti))*Mp)},rd=ii=>{ii.dispatchEvent(new Event(mc))},po=ii=>!ii||typeof ii!="object"?!1:(typeof ii.jquery!="undefined"&&(ii=ii[0]),typeof ii.nodeType!="undefined"),Ao=ii=>po(ii)?ii.jquery?ii[0]:ii:typeof ii=="string"&&ii.length>0?document.querySelector(nd(ii)):null,As=ii=>{if(!po(ii)||ii.getClientRects().length===0)return!1;let ei=getComputedStyle(ii).getPropertyValue("visibility")==="visible",ti=ii.closest("details:not([open])");if(!ti)return ei;if(ti!==ii){let ni=ii.closest("summary");if(ni&&ni.parentNode!==ti||ni===null)return!1}return ei},Do=ii=>!ii||ii.nodeType!==Node.ELEMENT_NODE||ii.classList.contains("disabled")?!0:typeof ii.disabled!="undefined"?ii.disabled:ii.hasAttribute("disabled")&&ii.getAttribute("disabled")!=="false",od=ii=>{if(!document.documentElement.attachShadow)return null;if(typeof ii.getRootNode=="function"){let ei=ii.getRootNode();return ei instanceof ShadowRoot?ei:null}return ii instanceof ShadowRoot?ii:ii.parentNode?od(ii.parentNode):null},Ua=()=>{},na=ii=>{ii.offsetHeight},sd=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,tc=[],Ip=ii=>{document.readyState==="loading"?(tc.length||document.addEventListener("DOMContentLoaded",()=>{for(let ei of tc)ei()}),tc.push(ii)):ii()},Gr=()=>document.documentElement.dir==="rtl",Qr=ii=>{Ip(()=>{let ei=sd();if(ei){let ti=ii.NAME,ni=ei.fn[ti];ei.fn[ti]=ii.jQueryInterface,ei.fn[ti].Constructor=ii,ei.fn[ti].noConflict=()=>(ei.fn[ti]=ni,ii.jQueryInterface)}})},Vn=(ii,ei=[],ti=ii)=>typeof ii=="function"?ii(...ei):ti,ad=(ii,ei,ti=!0)=>{if(!ti){Vn(ii);return}let ri=Rp(ei)+5,oi=!1,si=({target:ai})=>{ai===ei&&(oi=!0,ei.removeEventListener(mc,si),Vn(ii))};ei.addEventListener(mc,si),setTimeout(()=>{oi||rd(ei)},ri)},bc=(ii,ei,ti,ni)=>{let ri=ii.length,oi=ii.indexOf(ei);return oi===-1?!ti&&ni?ii[ri-1]:ii[0]:(oi+=ti?1:-1,ni&&(oi=(oi+ri)%ri),ii[Math.max(0,Math.min(oi,ri-1))])},Hp=/[^.]*(?=\..*)\.|.*/,Pp=/\..*/,Fp=/::\d+$/,ic={},Ou=1,ld={mouseenter:"mouseover",mouseleave:"mouseout"},$p=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"]);function cd(ii,ei){return ei&&`${ei}::${Ou++}`||ii.uidEvent||Ou++}function ud(ii){let ei=cd(ii);return ii.uidEvent=ei,ic[ei]=ic[ei]||{},ic[ei]}function Bp(ii,ei){return function ti(ni){return _c(ni,{delegateTarget:ii}),ti.oneOff&&wi.off(ii,ni.type,ei),ei.apply(ii,[ni])}}function zp(ii,ei,ti){return function ni(ri){let oi=ii.querySelectorAll(ei);for(let{target:si}=ri;si&&si!==this;si=si.parentNode)for(let ai of oi)if(ai===si)return _c(ri,{delegateTarget:si}),ni.oneOff&&wi.off(ii,ri.type,ei,ti),ti.apply(si,[ri])}}function dd(ii,ei,ti=null){return Object.values(ii).find(ni=>ni.callable===ei&&ni.delegationSelector===ti)}function fd(ii,ei,ti){let ni=typeof ei=="string",ri=ni?ti:ei||ti,oi=hd(ii);return $p.has(oi)||(oi=ii),[ni,ri,oi]}function Lu(ii,ei,ti,ni,ri){if(typeof ei!="string"||!ii)return;let[oi,si,ai]=fd(ei,ti,ni);ei in ld&&(si=(gi=>function(vi){if(!vi.relatedTarget||vi.relatedTarget!==vi.delegateTarget&&!vi.delegateTarget.contains(vi.relatedTarget))return gi.call(this,vi)})(si));let li=ud(ii),ui=li[ai]||(li[ai]={}),ci=dd(ui,si,oi?ti:null);if(ci){ci.oneOff=ci.oneOff&&ri;return}let di=cd(si,ei.replace(Hp,"")),pi=oi?zp(ii,ti,si):Bp(ii,si);pi.delegationSelector=oi?ti:null,pi.callable=si,pi.oneOff=ri,pi.uidEvent=di,ui[di]=pi,ii.addEventListener(ai,pi,oi)}function gc(ii,ei,ti,ni,ri){let oi=dd(ei[ti],ni,ri);oi&&(ii.removeEventListener(ti,oi,!!ri),delete ei[ti][oi.uidEvent])}function Vp(ii,ei,ti,ni){let ri=ei[ti]||{};for(let[oi,si]of Object.entries(ri))oi.includes(ni)&&gc(ii,ei,ti,si.callable,si.delegationSelector)}function hd(ii){return ii=ii.replace(Pp,""),ld[ii]||ii}var wi={on(ii,ei,ti,ni){Lu(ii,ei,ti,ni,!1)},one(ii,ei,ti,ni){Lu(ii,ei,ti,ni,!0)},off(ii,ei,ti,ni){if(typeof ei!="string"||!ii)return;let[ri,oi,si]=fd(ei,ti,ni),ai=si!==ei,li=ud(ii),ui=li[si]||{},ci=ei.startsWith(".");if(typeof oi!="undefined"){if(!Object.keys(ui).length)return;gc(ii,li,si,oi,ri?ti:null);return}if(ci)for(let di of Object.keys(li))Vp(ii,li,di,ei.slice(1));for(let[di,pi]of Object.entries(ui)){let yi=di.replace(Fp,"");(!ai||ei.includes(yi))&&gc(ii,li,si,pi.callable,pi.delegationSelector)}},trigger(ii,ei,ti){if(typeof ei!="string"||!ii)return null;let ni=sd(),ri=hd(ei),oi=ei!==ri,si=null,ai=!0,li=!0,ui=!1;oi&&ni&&(si=ni.Event(ei,ti),ni(ii).trigger(si),ai=!si.isPropagationStopped(),li=!si.isImmediatePropagationStopped(),ui=si.isDefaultPrevented());let ci=_c(new Event(ei,{bubbles:ai,cancelable:!0}),ti);return ui&&ci.preventDefault(),li&&ii.dispatchEvent(ci),ci.defaultPrevented&&si&&si.preventDefault(),ci}};function _c(ii,ei={}){for(let[ti,ni]of Object.entries(ei))try{ii[ti]=ni}catch(ri){Object.defineProperty(ii,ti,{configurable:!0,get(){return ni}})}return ii}function Mu(ii){if(ii==="true")return!0;if(ii==="false")return!1;if(ii===Number(ii).toString())return Number(ii);if(ii===""||ii==="null")return null;if(typeof ii!="string")return ii;try{return JSON.parse(decodeURIComponent(ii))}catch(ei){return ii}}function nc(ii){return ii.replace(/[A-Z]/g,ei=>`-${ei.toLowerCase()}`)}var mo={setDataAttribute(ii,ei,ti){ii.setAttribute(`data-bs-${nc(ei)}`,ti)},removeDataAttribute(ii,ei){ii.removeAttribute(`data-bs-${nc(ei)}`)},getDataAttributes(ii){if(!ii)return{};let ei={},ti=Object.keys(ii.dataset).filter(ni=>ni.startsWith("bs")&&!ni.startsWith("bsConfig"));for(let ni of ti){let ri=ni.replace(/^bs/,"");ri=ri.charAt(0).toLowerCase()+ri.slice(1,ri.length),ei[ri]=Mu(ii.dataset[ni])}return ei},getDataAttribute(ii,ei){return Mu(ii.getAttribute(`data-bs-${nc(ei)}`))}},es=class{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(ei){return ei=this._mergeConfigObj(ei),ei=this._configAfterMerge(ei),this._typeCheckConfig(ei),ei}_configAfterMerge(ei){return ei}_mergeConfigObj(ei,ti){let ni=po(ti)?mo.getDataAttribute(ti,"config"):{};return Di(Di(Di(Di({},this.constructor.Default),typeof ni=="object"?ni:{}),po(ti)?mo.getDataAttributes(ti):{}),typeof ei=="object"?ei:{})}_typeCheckConfig(ei,ti=this.constructor.DefaultType){for(let[ni,ri]of Object.entries(ti)){let oi=ei[ni],si=po(oi)?"element":kp(oi);if(!new RegExp(ri).test(si))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${ni}" provided type "${si}" but expected type "${ri}".`)}}},jp="5.3.3",Qn=class extends es{constructor(ei,ti){super(),ei=Ao(ei),ei&&(this._element=ei,this._config=this._getConfig(ti),ec.set(this._element,this.constructor.DATA_KEY,this))}dispose(){ec.remove(this._element,this.constructor.DATA_KEY),wi.off(this._element,this.constructor.EVENT_KEY);for(let ei of Object.getOwnPropertyNames(this))this[ei]=null}_queueCallback(ei,ti,ni=!0){ad(ei,ti,ni)}_getConfig(ei){return ei=this._mergeConfigObj(ei,this._element),ei=this._configAfterMerge(ei),this._typeCheckConfig(ei),ei}static getInstance(ei){return ec.get(Ao(ei),this.DATA_KEY)}static getOrCreateInstance(ei,ti={}){return this.getInstance(ei)||new this(ei,typeof ti=="object"?ti:null)}static get VERSION(){return jp}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(ei){return`${ei}${this.EVENT_KEY}`}},rc=ii=>{let ei=ii.getAttribute("data-bs-target");if(!ei||ei==="#"){let ti=ii.getAttribute("href");if(!ti||!ti.includes("#")&&!ti.startsWith("."))return null;ti.includes("#")&&!ti.startsWith("#")&&(ti=`#${ti.split("#")[1]}`),ei=ti&&ti!=="#"?ti.trim():null}return ei?ei.split(",").map(ti=>nd(ti)).join(","):null},Wi={find(ii,ei=document.documentElement){return[].concat(...Element.prototype.querySelectorAll.call(ei,ii))},findOne(ii,ei=document.documentElement){return Element.prototype.querySelector.call(ei,ii)},children(ii,ei){return[].concat(...ii.children).filter(ti=>ti.matches(ei))},parents(ii,ei){let ti=[],ni=ii.parentNode.closest(ei);for(;ni;)ti.push(ni),ni=ni.parentNode.closest(ei);return ti},prev(ii,ei){let ti=ii.previousElementSibling;for(;ti;){if(ti.matches(ei))return[ti];ti=ti.previousElementSibling}return[]},next(ii,ei){let ti=ii.nextElementSibling;for(;ti;){if(ti.matches(ei))return[ti];ti=ti.nextElementSibling}return[]},focusableChildren(ii){let ei=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(ti=>`${ti}:not([tabindex^="-"])`).join(",");return this.find(ei,ii).filter(ti=>!Do(ti)&&As(ti))},getSelectorFromElement(ii){let ei=rc(ii);return ei&&Wi.findOne(ei)?ei:null},getElementFromSelector(ii){let ei=rc(ii);return ei?Wi.findOne(ei):null},getMultipleElementsFromSelector(ii){let ei=rc(ii);return ei?Wi.find(ei):[]}},el=(ii,ei="hide")=>{let ti=`click.dismiss${ii.EVENT_KEY}`,ni=ii.NAME;wi.on(document,ti,`[data-bs-dismiss="${ni}"]`,function(ri){if(["A","AREA"].includes(this.tagName)&&ri.preventDefault(),Do(this))return;let oi=Wi.getElementFromSelector(this)||this.closest(`.${ni}`);ii.getOrCreateInstance(oi)[ei]()})},qp="alert",Wp="bs.alert",pd=`.${Wp}`,Up=`close${pd}`,Yp=`closed${pd}`,Gp="fade",Kp="show",Ya=class ii extends Qn{static get NAME(){return qp}close(){if(wi.trigger(this._element,Up).defaultPrevented)return;this._element.classList.remove(Kp);let ti=this._element.classList.contains(Gp);this._queueCallback(()=>this._destroyElement(),this._element,ti)}_destroyElement(){this._element.remove(),wi.trigger(this._element,Yp),this.dispose()}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this);if(typeof ei=="string"){if(ti[ei]===void 0||ei.startsWith("_")||ei==="constructor")throw new TypeError(`No method named "${ei}"`);ti[ei](this)}})}};el(Ya,"close");Qr(Ya);var Qp="button",Xp="bs.button",Jp=`.${Xp}`,Zp=".data-api",em="active",ku='[data-bs-toggle="button"]',tm=`click${Jp}${Zp}`,Ga=class ii extends Qn{static get NAME(){return Qp}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle(em))}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this);ei==="toggle"&&ti[ei]()})}};wi.on(document,tm,ku,ii=>{ii.preventDefault();let ei=ii.target.closest(ku);Ga.getOrCreateInstance(ei).toggle()});Qr(Ga);var im="swipe",Ds=".bs.swipe",nm=`touchstart${Ds}`,rm=`touchmove${Ds}`,om=`touchend${Ds}`,sm=`pointerdown${Ds}`,am=`pointerup${Ds}`,lm="touch",cm="pen",um="pointer-event",dm=40,fm={endCallback:null,leftCallback:null,rightCallback:null},hm={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"},Ka=class ii extends es{constructor(ei,ti){super(),this._element=ei,!(!ei||!ii.isSupported())&&(this._config=this._getConfig(ti),this._deltaX=0,this._supportPointerEvents=!!window.PointerEvent,this._initEvents())}static get Default(){return fm}static get DefaultType(){return hm}static get NAME(){return im}dispose(){wi.off(this._element,Ds)}_start(ei){if(!this._supportPointerEvents){this._deltaX=ei.touches[0].clientX;return}this._eventIsPointerPenTouch(ei)&&(this._deltaX=ei.clientX)}_end(ei){this._eventIsPointerPenTouch(ei)&&(this._deltaX=ei.clientX-this._deltaX),this._handleSwipe(),Vn(this._config.endCallback)}_move(ei){this._deltaX=ei.touches&&ei.touches.length>1?0:ei.touches[0].clientX-this._deltaX}_handleSwipe(){let ei=Math.abs(this._deltaX);if(ei<=dm)return;let ti=ei/this._deltaX;this._deltaX=0,ti&&Vn(ti>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(wi.on(this._element,sm,ei=>this._start(ei)),wi.on(this._element,am,ei=>this._end(ei)),this._element.classList.add(um)):(wi.on(this._element,nm,ei=>this._start(ei)),wi.on(this._element,rm,ei=>this._move(ei)),wi.on(this._element,om,ei=>this._end(ei)))}_eventIsPointerPenTouch(ei){return this._supportPointerEvents&&(ei.pointerType===cm||ei.pointerType===lm)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}},pm="carousel",mm="bs.carousel",ko=`.${mm}`,md=".data-api",gm="ArrowLeft",vm="ArrowRight",ym=500,Zs="next",Es="prev",xs="left",qa="right",bm=`slide${ko}`,oc=`slid${ko}`,_m=`keydown${ko}`,Em=`mouseenter${ko}`,wm=`mouseleave${ko}`,xm=`dragstart${ko}`,Tm=`load${ko}${md}`,Cm=`click${ko}${md}`,gd="carousel",Fa="active",Sm="slide",Am="carousel-item-end",Dm="carousel-item-start",Om="carousel-item-next",Lm="carousel-item-prev",vd=".active",yd=".carousel-item",Mm=vd+yd,km=".carousel-item img",Nm=".carousel-indicators",Rm="[data-bs-slide], [data-bs-slide-to]",Im='[data-bs-ride="carousel"]',Hm={[gm]:qa,[vm]:xs},Pm={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Fm={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"},ta=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=Wi.findOne(Nm,this._element),this._addEventListeners(),this._config.ride===gd&&this.cycle()}static get Default(){return Pm}static get DefaultType(){return Fm}static get NAME(){return pm}next(){this._slide(Zs)}nextWhenVisible(){!document.hidden&&As(this._element)&&this.next()}prev(){this._slide(Es)}pause(){this._isSliding&&rd(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){if(this._config.ride){if(this._isSliding){wi.one(this._element,oc,()=>this.cycle());return}this.cycle()}}to(ei){let ti=this._getItems();if(ei>ti.length-1||ei<0)return;if(this._isSliding){wi.one(this._element,oc,()=>this.to(ei));return}let ni=this._getItemIndex(this._getActive());if(ni===ei)return;let ri=ei>ni?Zs:Es;this._slide(ri,ti[ei])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(ei){return ei.defaultInterval=ei.interval,ei}_addEventListeners(){this._config.keyboard&&wi.on(this._element,_m,ei=>this._keydown(ei)),this._config.pause==="hover"&&(wi.on(this._element,Em,()=>this.pause()),wi.on(this._element,wm,()=>this._maybeEnableCycle())),this._config.touch&&Ka.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(let ni of Wi.find(km,this._element))wi.on(ni,xm,ri=>ri.preventDefault());let ti={leftCallback:()=>this._slide(this._directionToOrder(xs)),rightCallback:()=>this._slide(this._directionToOrder(qa)),endCallback:()=>{this._config.pause==="hover"&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),ym+this._config.interval))}};this._swipeHelper=new Ka(this._element,ti)}_keydown(ei){if(/input|textarea/i.test(ei.target.tagName))return;let ti=Hm[ei.key];ti&&(ei.preventDefault(),this._slide(this._directionToOrder(ti)))}_getItemIndex(ei){return this._getItems().indexOf(ei)}_setActiveIndicatorElement(ei){if(!this._indicatorsElement)return;let ti=Wi.findOne(vd,this._indicatorsElement);ti.classList.remove(Fa),ti.removeAttribute("aria-current");let ni=Wi.findOne(`[data-bs-slide-to="${ei}"]`,this._indicatorsElement);ni&&(ni.classList.add(Fa),ni.setAttribute("aria-current","true"))}_updateInterval(){let ei=this._activeElement||this._getActive();if(!ei)return;let ti=Number.parseInt(ei.getAttribute("data-bs-interval"),10);this._config.interval=ti||this._config.defaultInterval}_slide(ei,ti=null){if(this._isSliding)return;let ni=this._getActive(),ri=ei===Zs,oi=ti||bc(this._getItems(),ni,ri,this._config.wrap);if(oi===ni)return;let si=this._getItemIndex(oi),ai=yi=>wi.trigger(this._element,yi,{relatedTarget:oi,direction:this._orderToDirection(ei),from:this._getItemIndex(ni),to:si});if(ai(bm).defaultPrevented||!ni||!oi)return;let ui=!!this._interval;this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(si),this._activeElement=oi;let ci=ri?Dm:Am,di=ri?Om:Lm;oi.classList.add(di),na(oi),ni.classList.add(ci),oi.classList.add(ci);let pi=()=>{oi.classList.remove(ci,di),oi.classList.add(Fa),ni.classList.remove(Fa,di,ci),this._isSliding=!1,ai(oc)};this._queueCallback(pi,ni,this._isAnimated()),ui&&this.cycle()}_isAnimated(){return this._element.classList.contains(Sm)}_getActive(){return Wi.findOne(Mm,this._element)}_getItems(){return Wi.find(yd,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(ei){return Gr()?ei===xs?Es:Zs:ei===xs?Zs:Es}_orderToDirection(ei){return Gr()?ei===Es?xs:qa:ei===Es?qa:xs}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="number"){ti.to(ei);return}if(typeof ei=="string"){if(ti[ei]===void 0||ei.startsWith("_")||ei==="constructor")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}};wi.on(document,Cm,Rm,function(ii){let ei=Wi.getElementFromSelector(this);if(!ei||!ei.classList.contains(gd))return;ii.preventDefault();let ti=ta.getOrCreateInstance(ei),ni=this.getAttribute("data-bs-slide-to");if(ni){ti.to(ni),ti._maybeEnableCycle();return}if(mo.getDataAttribute(this,"slide")==="next"){ti.next(),ti._maybeEnableCycle();return}ti.prev(),ti._maybeEnableCycle()});wi.on(window,Tm,()=>{let ii=Wi.find(Im);for(let ei of ii)ta.getOrCreateInstance(ei)});Qr(ta);var $m="collapse",Bm="bs.collapse",ra=`.${Bm}`,zm=".data-api",Vm=`show${ra}`,jm=`shown${ra}`,qm=`hide${ra}`,Wm=`hidden${ra}`,Um=`click${ra}${zm}`,sc="show",Cs="collapse",$a="collapsing",Ym="collapsed",Gm=`:scope .${Cs} .${Cs}`,Km="collapse-horizontal",Qm="width",Xm="height",Jm=".collapse.show, .collapse.collapsing",vc='[data-bs-toggle="collapse"]',Zm={parent:null,toggle:!0},eg={parent:"(null|element)",toggle:"boolean"},Oo=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._isTransitioning=!1,this._triggerArray=[];let ni=Wi.find(vc);for(let ri of ni){let oi=Wi.getSelectorFromElement(ri),si=Wi.find(oi).filter(ai=>ai===this._element);oi!==null&&si.length&&this._triggerArray.push(ri)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Zm}static get DefaultType(){return eg}static get NAME(){return $m}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let ei=[];if(this._config.parent&&(ei=this._getFirstLevelChildren(Jm).filter(ai=>ai!==this._element).map(ai=>ii.getOrCreateInstance(ai,{toggle:!1}))),ei.length&&ei[0]._isTransitioning||wi.trigger(this._element,Vm).defaultPrevented)return;for(let ai of ei)ai.hide();let ni=this._getDimension();this._element.classList.remove(Cs),this._element.classList.add($a),this._element.style[ni]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;let ri=()=>{this._isTransitioning=!1,this._element.classList.remove($a),this._element.classList.add(Cs,sc),this._element.style[ni]="",wi.trigger(this._element,jm)},si=`scroll${ni[0].toUpperCase()+ni.slice(1)}`;this._queueCallback(ri,this._element,!0),this._element.style[ni]=`${this._element[si]}px`}hide(){if(this._isTransitioning||!this._isShown()||wi.trigger(this._element,qm).defaultPrevented)return;let ti=this._getDimension();this._element.style[ti]=`${this._element.getBoundingClientRect()[ti]}px`,na(this._element),this._element.classList.add($a),this._element.classList.remove(Cs,sc);for(let ri of this._triggerArray){let oi=Wi.getElementFromSelector(ri);oi&&!this._isShown(oi)&&this._addAriaAndCollapsedClass([ri],!1)}this._isTransitioning=!0;let ni=()=>{this._isTransitioning=!1,this._element.classList.remove($a),this._element.classList.add(Cs),wi.trigger(this._element,Wm)};this._element.style[ti]="",this._queueCallback(ni,this._element,!0)}_isShown(ei=this._element){return ei.classList.contains(sc)}_configAfterMerge(ei){return ei.toggle=!!ei.toggle,ei.parent=Ao(ei.parent),ei}_getDimension(){return this._element.classList.contains(Km)?Qm:Xm}_initializeChildren(){if(!this._config.parent)return;let ei=this._getFirstLevelChildren(vc);for(let ti of ei){let ni=Wi.getElementFromSelector(ti);ni&&this._addAriaAndCollapsedClass([ti],this._isShown(ni))}}_getFirstLevelChildren(ei){let ti=Wi.find(Gm,this._config.parent);return Wi.find(ei,this._config.parent).filter(ni=>!ti.includes(ni))}_addAriaAndCollapsedClass(ei,ti){if(ei.length)for(let ni of ei)ni.classList.toggle(Ym,!ti),ni.setAttribute("aria-expanded",ti)}static jQueryInterface(ei){let ti={};return typeof ei=="string"&&/show|hide/.test(ei)&&(ti.toggle=!1),this.each(function(){let ni=ii.getOrCreateInstance(this,ti);if(typeof ei=="string"){if(typeof ni[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ni[ei]()}})}};wi.on(document,Um,vc,function(ii){(ii.target.tagName==="A"||ii.delegateTarget&&ii.delegateTarget.tagName==="A")&&ii.preventDefault();for(let ei of Wi.getMultipleElementsFromSelector(this))Oo.getOrCreateInstance(ei,{toggle:!1}).toggle()});Qr(Oo);var Nu="dropdown",tg="bs.dropdown",is=`.${tg}`,Ec=".data-api",ig="Escape",Ru="Tab",ng="ArrowUp",Iu="ArrowDown",rg=2,og=`hide${is}`,sg=`hidden${is}`,ag=`show${is}`,lg=`shown${is}`,bd=`click${is}${Ec}`,_d=`keydown${is}${Ec}`,cg=`keyup${is}${Ec}`,Ts="show",ug="dropup",dg="dropend",fg="dropstart",hg="dropup-center",pg="dropdown-center",Jo='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',mg=`${Jo}.${Ts}`,Wa=".dropdown-menu",gg=".navbar",vg=".navbar-nav",yg=".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",bg=Gr()?"top-end":"top-start",_g=Gr()?"top-start":"top-end",Eg=Gr()?"bottom-end":"bottom-start",wg=Gr()?"bottom-start":"bottom-end",xg=Gr()?"left-start":"right-start",Tg=Gr()?"right-start":"left-start",Cg="top",Sg="bottom",Ag={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},Dg={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"},Lo=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._popper=null,this._parent=this._element.parentNode,this._menu=Wi.next(this._element,Wa)[0]||Wi.prev(this._element,Wa)[0]||Wi.findOne(Wa,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return Ag}static get DefaultType(){return Dg}static get NAME(){return Nu}toggle(){return this._isShown()?this.hide():this.show()}show(){if(Do(this._element)||this._isShown())return;let ei={relatedTarget:this._element};if(!wi.trigger(this._element,ag,ei).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(vg))for(let ni of[].concat(...document.body.children))wi.on(ni,"mouseover",Ua);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Ts),this._element.classList.add(Ts),wi.trigger(this._element,lg,ei)}}hide(){if(Do(this._element)||!this._isShown())return;let ei={relatedTarget:this._element};this._completeHide(ei)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(ei){if(!wi.trigger(this._element,og,ei).defaultPrevented){if("ontouchstart"in document.documentElement)for(let ni of[].concat(...document.body.children))wi.off(ni,"mouseover",Ua);this._popper&&this._popper.destroy(),this._menu.classList.remove(Ts),this._element.classList.remove(Ts),this._element.setAttribute("aria-expanded","false"),mo.removeDataAttribute(this._menu,"popper"),wi.trigger(this._element,sg,ei)}}_getConfig(ei){if(ei=super._getConfig(ei),typeof ei.reference=="object"&&!po(ei.reference)&&typeof ei.reference.getBoundingClientRect!="function")throw new TypeError(`${Nu.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return ei}_createPopper(){if(typeof Pa=="undefined")throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let ei=this._element;this._config.reference==="parent"?ei=this._parent:po(this._config.reference)?ei=Ao(this._config.reference):typeof this._config.reference=="object"&&(ei=this._config.reference);let ti=this._getPopperConfig();this._popper=Js(ei,this._menu,ti)}_isShown(){return this._menu.classList.contains(Ts)}_getPlacement(){let ei=this._parent;if(ei.classList.contains(dg))return xg;if(ei.classList.contains(fg))return Tg;if(ei.classList.contains(hg))return Cg;if(ei.classList.contains(pg))return Sg;let ti=getComputedStyle(this._menu).getPropertyValue("--bs-position").trim()==="end";return ei.classList.contains(ug)?ti?_g:bg:ti?wg:Eg}_detectNavbar(){return this._element.closest(gg)!==null}_getOffset(){let{offset:ei}=this._config;return typeof ei=="string"?ei.split(",").map(ti=>Number.parseInt(ti,10)):typeof ei=="function"?ti=>ei(ti,this._element):ei}_getPopperConfig(){let ei={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||this._config.display==="static")&&(mo.setDataAttribute(this._menu,"popper","static"),ei.modifiers=[{name:"applyStyles",enabled:!1}]),Di(Di({},ei),Vn(this._config.popperConfig,[ei]))}_selectMenuItem({key:ei,target:ti}){let ni=Wi.find(yg,this._menu).filter(ri=>As(ri));ni.length&&bc(ni,ti,ei===Iu,!ni.includes(ti)).focus()}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(typeof ti[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}static clearMenus(ei){if(ei.button===rg||ei.type==="keyup"&&ei.key!==Ru)return;let ti=Wi.find(mg);for(let ni of ti){let ri=ii.getInstance(ni);if(!ri||ri._config.autoClose===!1)continue;let oi=ei.composedPath(),si=oi.includes(ri._menu);if(oi.includes(ri._element)||ri._config.autoClose==="inside"&&!si||ri._config.autoClose==="outside"&&si||ri._menu.contains(ei.target)&&(ei.type==="keyup"&&ei.key===Ru||/input|select|option|textarea|form/i.test(ei.target.tagName)))continue;let ai={relatedTarget:ri._element};ei.type==="click"&&(ai.clickEvent=ei),ri._completeHide(ai)}}static dataApiKeydownHandler(ei){let ti=/input|textarea/i.test(ei.target.tagName),ni=ei.key===ig,ri=[ng,Iu].includes(ei.key);if(!ri&&!ni||ti&&!ni)return;ei.preventDefault();let oi=this.matches(Jo)?this:Wi.prev(this,Jo)[0]||Wi.next(this,Jo)[0]||Wi.findOne(Jo,ei.delegateTarget.parentNode),si=ii.getOrCreateInstance(oi);if(ri){ei.stopPropagation(),si.show(),si._selectMenuItem(ei);return}si._isShown()&&(ei.stopPropagation(),si.hide(),oi.focus())}};wi.on(document,_d,Jo,Lo.dataApiKeydownHandler);wi.on(document,_d,Wa,Lo.dataApiKeydownHandler);wi.on(document,bd,Lo.clearMenus);wi.on(document,cg,Lo.clearMenus);wi.on(document,bd,Jo,function(ii){ii.preventDefault(),Lo.getOrCreateInstance(this).toggle()});Qr(Lo);var Ed="backdrop",Og="fade",Hu="show",Pu=`mousedown.bs.${Ed}`,Lg={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Mg={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"},Qa=class extends es{constructor(ei){super(),this._config=this._getConfig(ei),this._isAppended=!1,this._element=null}static get Default(){return Lg}static get DefaultType(){return Mg}static get NAME(){return Ed}show(ei){if(!this._config.isVisible){Vn(ei);return}this._append();let ti=this._getElement();this._config.isAnimated&&na(ti),ti.classList.add(Hu),this._emulateAnimation(()=>{Vn(ei)})}hide(ei){if(!this._config.isVisible){Vn(ei);return}this._getElement().classList.remove(Hu),this._emulateAnimation(()=>{this.dispose(),Vn(ei)})}dispose(){this._isAppended&&(wi.off(this._element,Pu),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){let ei=document.createElement("div");ei.className=this._config.className,this._config.isAnimated&&ei.classList.add(Og),this._element=ei}return this._element}_configAfterMerge(ei){return ei.rootElement=Ao(ei.rootElement),ei}_append(){if(this._isAppended)return;let ei=this._getElement();this._config.rootElement.append(ei),wi.on(ei,Pu,()=>{Vn(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(ei){ad(ei,this._getElement(),this._config.isAnimated)}},kg="focustrap",Ng="bs.focustrap",Xa=`.${Ng}`,Rg=`focusin${Xa}`,Ig=`keydown.tab${Xa}`,Hg="Tab",Pg="forward",Fu="backward",Fg={autofocus:!0,trapElement:null},$g={autofocus:"boolean",trapElement:"element"},Ja=class extends es{constructor(ei){super(),this._config=this._getConfig(ei),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return Fg}static get DefaultType(){return $g}static get NAME(){return kg}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),wi.off(document,Xa),wi.on(document,Rg,ei=>this._handleFocusin(ei)),wi.on(document,Ig,ei=>this._handleKeydown(ei)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,wi.off(document,Xa))}_handleFocusin(ei){let{trapElement:ti}=this._config;if(ei.target===document||ei.target===ti||ti.contains(ei.target))return;let ni=Wi.focusableChildren(ti);ni.length===0?ti.focus():this._lastTabNavDirection===Fu?ni[ni.length-1].focus():ni[0].focus()}_handleKeydown(ei){ei.key===Hg&&(this._lastTabNavDirection=ei.shiftKey?Fu:Pg)}},$u=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Bu=".sticky-top",Ba="padding-right",zu="margin-right",ia=class{constructor(){this._element=document.body}getWidth(){let ei=document.documentElement.clientWidth;return Math.abs(window.innerWidth-ei)}hide(){let ei=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ba,ti=>ti+ei),this._setElementAttributes($u,Ba,ti=>ti+ei),this._setElementAttributes(Bu,zu,ti=>ti-ei)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ba),this._resetElementAttributes($u,Ba),this._resetElementAttributes(Bu,zu)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(ei,ti,ni){let ri=this.getWidth(),oi=si=>{if(si!==this._element&&window.innerWidth>si.clientWidth+ri)return;this._saveInitialAttribute(si,ti);let ai=window.getComputedStyle(si).getPropertyValue(ti);si.style.setProperty(ti,`${ni(Number.parseFloat(ai))}px`)};this._applyManipulationCallback(ei,oi)}_saveInitialAttribute(ei,ti){let ni=ei.style.getPropertyValue(ti);ni&&mo.setDataAttribute(ei,ti,ni)}_resetElementAttributes(ei,ti){let ni=ri=>{let oi=mo.getDataAttribute(ri,ti);if(oi===null){ri.style.removeProperty(ti);return}mo.removeDataAttribute(ri,ti),ri.style.setProperty(ti,oi)};this._applyManipulationCallback(ei,ni)}_applyManipulationCallback(ei,ti){if(po(ei)){ti(ei);return}for(let ni of Wi.find(ei,this._element))ti(ni)}},Bg="modal",zg="bs.modal",Kr=`.${zg}`,Vg=".data-api",jg="Escape",qg=`hide${Kr}`,Wg=`hidePrevented${Kr}`,wd=`hidden${Kr}`,xd=`show${Kr}`,Ug=`shown${Kr}`,Yg=`resize${Kr}`,Gg=`click.dismiss${Kr}`,Kg=`mousedown.dismiss${Kr}`,Qg=`keydown.dismiss${Kr}`,Xg=`click${Kr}${Vg}`,Vu="modal-open",Jg="fade",ju="show",ac="modal-static",Zg=".modal.show",ev=".modal-dialog",tv=".modal-body",iv='[data-bs-toggle="modal"]',nv={backdrop:!0,focus:!0,keyboard:!0},rv={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"},io=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._dialog=Wi.findOne(ev,this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new ia,this._addEventListeners()}static get Default(){return nv}static get DefaultType(){return rv}static get NAME(){return Bg}toggle(ei){return this._isShown?this.hide():this.show(ei)}show(ei){this._isShown||this._isTransitioning||wi.trigger(this._element,xd,{relatedTarget:ei}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Vu),this._adjustDialog(),this._backdrop.show(()=>this._showElement(ei)))}hide(){!this._isShown||this._isTransitioning||wi.trigger(this._element,qg).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(ju),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated()))}dispose(){wi.off(window,Kr),wi.off(this._dialog,Kr),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Qa({isVisible:!!this._config.backdrop,isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ja({trapElement:this._element})}_showElement(ei){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;let ti=Wi.findOne(tv,this._dialog);ti&&(ti.scrollTop=0),na(this._element),this._element.classList.add(ju);let ni=()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,wi.trigger(this._element,Ug,{relatedTarget:ei})};this._queueCallback(ni,this._dialog,this._isAnimated())}_addEventListeners(){wi.on(this._element,Qg,ei=>{if(ei.key===jg){if(this._config.keyboard){this.hide();return}this._triggerBackdropTransition()}}),wi.on(window,Yg,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),wi.on(this._element,Kg,ei=>{wi.one(this._element,Gg,ti=>{if(!(this._element!==ei.target||this._element!==ti.target)){if(this._config.backdrop==="static"){this._triggerBackdropTransition();return}this._config.backdrop&&this.hide()}})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Vu),this._resetAdjustments(),this._scrollBar.reset(),wi.trigger(this._element,wd)})}_isAnimated(){return this._element.classList.contains(Jg)}_triggerBackdropTransition(){if(wi.trigger(this._element,Wg).defaultPrevented)return;let ti=this._element.scrollHeight>document.documentElement.clientHeight,ni=this._element.style.overflowY;ni==="hidden"||this._element.classList.contains(ac)||(ti||(this._element.style.overflowY="hidden"),this._element.classList.add(ac),this._queueCallback(()=>{this._element.classList.remove(ac),this._queueCallback(()=>{this._element.style.overflowY=ni},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){let ei=this._element.scrollHeight>document.documentElement.clientHeight,ti=this._scrollBar.getWidth(),ni=ti>0;if(ni&&!ei){let ri=Gr()?"paddingLeft":"paddingRight";this._element.style[ri]=`${ti}px`}if(!ni&&ei){let ri=Gr()?"paddingRight":"paddingLeft";this._element.style[ri]=`${ti}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(ei,ti){return this.each(function(){let ni=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(typeof ni[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ni[ei](ti)}})}};wi.on(document,Xg,iv,function(ii){let ei=Wi.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&ii.preventDefault(),wi.one(ei,xd,ri=>{ri.defaultPrevented||wi.one(ei,wd,()=>{As(this)&&this.focus()})});let ti=Wi.findOne(Zg);ti&&io.getInstance(ti).hide(),io.getOrCreateInstance(ei).toggle(this)});el(io);Qr(io);var ov="offcanvas",sv="bs.offcanvas",yo=`.${sv}`,Td=".data-api",av=`load${yo}${Td}`,lv="Escape",qu="show",Wu="showing",Uu="hiding",cv="offcanvas-backdrop",Cd=".offcanvas.show",uv=`show${yo}`,dv=`shown${yo}`,fv=`hide${yo}`,Yu=`hidePrevented${yo}`,Sd=`hidden${yo}`,hv=`resize${yo}`,pv=`click${yo}${Td}`,mv=`keydown.dismiss${yo}`,gv='[data-bs-toggle="offcanvas"]',vv={backdrop:!0,keyboard:!0,scroll:!1},yv={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"},Mo=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return vv}static get DefaultType(){return yv}static get NAME(){return ov}toggle(ei){return this._isShown?this.hide():this.show(ei)}show(ei){if(this._isShown||wi.trigger(this._element,uv,{relatedTarget:ei}).defaultPrevented)return;this._isShown=!0,this._backdrop.show(),this._config.scroll||new ia().hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Wu);let ni=()=>{(!this._config.scroll||this._config.backdrop)&&this._focustrap.activate(),this._element.classList.add(qu),this._element.classList.remove(Wu),wi.trigger(this._element,dv,{relatedTarget:ei})};this._queueCallback(ni,this._element,!0)}hide(){if(!this._isShown||wi.trigger(this._element,fv).defaultPrevented)return;this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Uu),this._backdrop.hide();let ti=()=>{this._element.classList.remove(qu,Uu),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||new ia().reset(),wi.trigger(this._element,Sd)};this._queueCallback(ti,this._element,!0)}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){let ei=()=>{if(this._config.backdrop==="static"){wi.trigger(this._element,Yu);return}this.hide()},ti=!!this._config.backdrop;return new Qa({className:cv,isVisible:ti,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:ti?ei:null})}_initializeFocusTrap(){return new Ja({trapElement:this._element})}_addEventListeners(){wi.on(this._element,mv,ei=>{if(ei.key===lv){if(this._config.keyboard){this.hide();return}wi.trigger(this._element,Yu)}})}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(ti[ei]===void 0||ei.startsWith("_")||ei==="constructor")throw new TypeError(`No method named "${ei}"`);ti[ei](this)}})}};wi.on(document,pv,gv,function(ii){let ei=Wi.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&ii.preventDefault(),Do(this))return;wi.one(ei,Sd,()=>{As(this)&&this.focus()});let ti=Wi.findOne(Cd);ti&&ti!==ei&&Mo.getInstance(ti).hide(),Mo.getOrCreateInstance(ei).toggle(this)});wi.on(window,av,()=>{for(let ii of Wi.find(Cd))Mo.getOrCreateInstance(ii).show()});wi.on(window,hv,()=>{for(let ii of Wi.find("[aria-modal][class*=show][class*=offcanvas-]"))getComputedStyle(ii).position!=="fixed"&&Mo.getOrCreateInstance(ii).hide()});el(Mo);Qr(Mo);var bv=/^aria-[\w-]*$/i,Ad={"*":["class","dir","id","lang","role",bv],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],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:[]},_v=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Ev=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,wv=(ii,ei)=>{let ti=ii.nodeName.toLowerCase();return ei.includes(ti)?_v.has(ti)?!!Ev.test(ii.nodeValue):!0:ei.filter(ni=>ni instanceof RegExp).some(ni=>ni.test(ti))};function xv(ii,ei,ti){if(!ii.length)return ii;if(ti&&typeof ti=="function")return ti(ii);let ri=new window.DOMParser().parseFromString(ii,"text/html"),oi=[].concat(...ri.body.querySelectorAll("*"));for(let si of oi){let ai=si.nodeName.toLowerCase();if(!Object.keys(ei).includes(ai)){si.remove();continue}let li=[].concat(...si.attributes),ui=[].concat(ei["*"]||[],ei[ai]||[]);for(let ci of li)wv(ci,ui)||si.removeAttribute(ci.nodeName)}return ri.body.innerHTML}var Tv="TemplateFactory",Cv={allowList:Ad,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Sv={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Av={entry:"(string|element|function|null)",selector:"(string|element)"},yc=class extends es{constructor(ei){super(),this._config=this._getConfig(ei)}static get Default(){return Cv}static get DefaultType(){return Sv}static get NAME(){return Tv}getContent(){return Object.values(this._config.content).map(ei=>this._resolvePossibleFunction(ei)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(ei){return this._checkContent(ei),this._config.content=Di(Di({},this._config.content),ei),this}toHtml(){let ei=document.createElement("div");ei.innerHTML=this._maybeSanitize(this._config.template);for(let[ri,oi]of Object.entries(this._config.content))this._setContent(ei,oi,ri);let ti=ei.children[0],ni=this._resolvePossibleFunction(this._config.extraClass);return ni&&ti.classList.add(...ni.split(" ")),ti}_typeCheckConfig(ei){super._typeCheckConfig(ei),this._checkContent(ei.content)}_checkContent(ei){for(let[ti,ni]of Object.entries(ei))super._typeCheckConfig({selector:ti,entry:ni},Av)}_setContent(ei,ti,ni){let ri=Wi.findOne(ni,ei);if(ri){if(ti=this._resolvePossibleFunction(ti),!ti){ri.remove();return}if(po(ti)){this._putElementInTemplate(Ao(ti),ri);return}if(this._config.html){ri.innerHTML=this._maybeSanitize(ti);return}ri.textContent=ti}}_maybeSanitize(ei){return this._config.sanitize?xv(ei,this._config.allowList,this._config.sanitizeFn):ei}_resolvePossibleFunction(ei){return Vn(ei,[this])}_putElementInTemplate(ei,ti){if(this._config.html){ti.innerHTML="",ti.append(ei);return}ti.textContent=ei.textContent}},Dv="tooltip",Ov=new Set(["sanitize","allowList","sanitizeFn"]),lc="fade",Lv="modal",za="show",Mv=".tooltip-inner",Gu=`.${Lv}`,Ku="hide.bs.modal",ea="hover",cc="focus",kv="click",Nv="manual",Rv="hide",Iv="hidden",Hv="show",Pv="shown",Fv="inserted",$v="click",Bv="focusin",zv="focusout",Vv="mouseenter",jv="mouseleave",qv={AUTO:"auto",TOP:"top",RIGHT:Gr()?"left":"right",BOTTOM:"bottom",LEFT:Gr()?"right":"left"},Wv={allowList:Ad,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},Uv={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"},go=class ii extends Qn{constructor(ei,ti){if(typeof Pa=="undefined")throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(ei,ti),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Wv}static get DefaultType(){return Uv}static get NAME(){return Dv}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){if(this._isEnabled){if(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()){this._leave();return}this._enter()}}dispose(){clearTimeout(this._timeout),wi.off(this._element.closest(Gu),Ku,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if(this._element.style.display==="none")throw new Error("Please use show on visible elements");if(!(this._isWithContent()&&this._isEnabled))return;let ei=wi.trigger(this._element,this.constructor.eventName(Hv)),ni=(od(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(ei.defaultPrevented||!ni)return;this._disposePopper();let ri=this._getTipElement();this._element.setAttribute("aria-describedby",ri.getAttribute("id"));let{container:oi}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(oi.append(ri),wi.trigger(this._element,this.constructor.eventName(Fv))),this._popper=this._createPopper(ri),ri.classList.add(za),"ontouchstart"in document.documentElement)for(let ai of[].concat(...document.body.children))wi.on(ai,"mouseover",Ua);let si=()=>{wi.trigger(this._element,this.constructor.eventName(Pv)),this._isHovered===!1&&this._leave(),this._isHovered=!1};this._queueCallback(si,this.tip,this._isAnimated())}hide(){if(!this._isShown()||wi.trigger(this._element,this.constructor.eventName(Rv)).defaultPrevented)return;if(this._getTipElement().classList.remove(za),"ontouchstart"in document.documentElement)for(let ri of[].concat(...document.body.children))wi.off(ri,"mouseover",Ua);this._activeTrigger[kv]=!1,this._activeTrigger[cc]=!1,this._activeTrigger[ea]=!1,this._isHovered=null;let ni=()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),wi.trigger(this._element,this.constructor.eventName(Iv)))};this._queueCallback(ni,this.tip,this._isAnimated())}update(){this._popper&&this._popper.update()}_isWithContent(){return!!this._getTitle()}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(ei){let ti=this._getTemplateFactory(ei).toHtml();if(!ti)return null;ti.classList.remove(lc,za),ti.classList.add(`bs-${this.constructor.NAME}-auto`);let ni=Np(this.constructor.NAME).toString();return ti.setAttribute("id",ni),this._isAnimated()&&ti.classList.add(lc),ti}setContent(ei){this._newContent=ei,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(ei){return this._templateFactory?this._templateFactory.changeContent(ei):this._templateFactory=new yc(sn(Di({},this._config),{content:ei,extraClass:this._resolvePossibleFunction(this._config.customClass)})),this._templateFactory}_getContentForTemplate(){return{[Mv]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(ei){return this.constructor.getOrCreateInstance(ei.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(lc)}_isShown(){return this.tip&&this.tip.classList.contains(za)}_createPopper(ei){let ti=Vn(this._config.placement,[this,ei,this._element]),ni=qv[ti.toUpperCase()];return Js(this._element,ei,this._getPopperConfig(ni))}_getOffset(){let{offset:ei}=this._config;return typeof ei=="string"?ei.split(",").map(ti=>Number.parseInt(ti,10)):typeof ei=="function"?ti=>ei(ti,this._element):ei}_resolvePossibleFunction(ei){return Vn(ei,[this._element])}_getPopperConfig(ei){let ti={placement:ei,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:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:ni=>{this._getTipElement().setAttribute("data-popper-placement",ni.state.placement)}}]};return Di(Di({},ti),Vn(this._config.popperConfig,[ti]))}_setListeners(){let ei=this._config.trigger.split(" ");for(let ti of ei)if(ti==="click")wi.on(this._element,this.constructor.eventName($v),this._config.selector,ni=>{this._initializeOnDelegatedTarget(ni).toggle()});else if(ti!==Nv){let ni=ti===ea?this.constructor.eventName(Vv):this.constructor.eventName(Bv),ri=ti===ea?this.constructor.eventName(jv):this.constructor.eventName(zv);wi.on(this._element,ni,this._config.selector,oi=>{let si=this._initializeOnDelegatedTarget(oi);si._activeTrigger[oi.type==="focusin"?cc:ea]=!0,si._enter()}),wi.on(this._element,ri,this._config.selector,oi=>{let si=this._initializeOnDelegatedTarget(oi);si._activeTrigger[oi.type==="focusout"?cc:ea]=si._element.contains(oi.relatedTarget),si._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},wi.on(this._element.closest(Gu),Ku,this._hideModalHandler)}_fixTitle(){let ei=this._element.getAttribute("title");ei&&(!this._element.getAttribute("aria-label")&&!this._element.textContent.trim()&&this._element.setAttribute("aria-label",ei),this._element.setAttribute("data-bs-original-title",ei),this._element.removeAttribute("title"))}_enter(){if(this._isShown()||this._isHovered){this._isHovered=!0;return}this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show)}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide))}_setTimeout(ei,ti){clearTimeout(this._timeout),this._timeout=setTimeout(ei,ti)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(ei){let ti=mo.getDataAttributes(this._element);for(let ni of Object.keys(ti))Ov.has(ni)&&delete ti[ni];return ei=Di(Di({},ti),typeof ei=="object"&&ei?ei:{}),ei=this._mergeConfigObj(ei),ei=this._configAfterMerge(ei),this._typeCheckConfig(ei),ei}_configAfterMerge(ei){return ei.container=ei.container===!1?document.body:Ao(ei.container),typeof ei.delay=="number"&&(ei.delay={show:ei.delay,hide:ei.delay}),typeof ei.title=="number"&&(ei.title=ei.title.toString()),typeof ei.content=="number"&&(ei.content=ei.content.toString()),ei}_getDelegateConfig(){let ei={};for(let[ti,ni]of Object.entries(this._config))this.constructor.Default[ti]!==ni&&(ei[ti]=ni);return ei.selector=!1,ei.trigger="manual",ei}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(typeof ti[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}};Qr(go);var Yv="popover",Gv=".popover-header",Kv=".popover-body",Qv=sn(Di({},go.Default),{content:"",offset:[0,8],placement:"right",template:'',trigger:"click"}),Xv=sn(Di({},go.DefaultType),{content:"(null|string|element|function)"}),Ss=class ii extends go{static get Default(){return Qv}static get DefaultType(){return Xv}static get NAME(){return Yv}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[Gv]:this._getTitle(),[Kv]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(typeof ti[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}};Qr(Ss);var Jv="scrollspy",Zv="bs.scrollspy",wc=`.${Zv}`,ey=".data-api",ty=`activate${wc}`,Qu=`click${wc}`,iy=`load${wc}${ey}`,ny="dropdown-item",ws="active",ry='[data-bs-spy="scroll"]',uc="[href]",oy=".nav, .list-group",Xu=".nav-link",sy=".nav-item",ay=".list-group-item",ly=`${Xu}, ${sy} > ${Xu}, ${ay}`,cy=".dropdown",uy=".dropdown-toggle",dy={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},fy={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"},Za=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement=getComputedStyle(this._element).overflowY==="visible"?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return dy}static get DefaultType(){return fy}static get NAME(){return Jv}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(let ei of this._observableSections.values())this._observer.observe(ei)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(ei){return ei.target=Ao(ei.target)||document.body,ei.rootMargin=ei.offset?`${ei.offset}px 0px -30%`:ei.rootMargin,typeof ei.threshold=="string"&&(ei.threshold=ei.threshold.split(",").map(ti=>Number.parseFloat(ti))),ei}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(wi.off(this._config.target,Qu),wi.on(this._config.target,Qu,uc,ei=>{let ti=this._observableSections.get(ei.target.hash);if(ti){ei.preventDefault();let ni=this._rootElement||window,ri=ti.offsetTop-this._element.offsetTop;if(ni.scrollTo){ni.scrollTo({top:ri,behavior:"smooth"});return}ni.scrollTop=ri}}))}_getNewObserver(){let ei={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(ti=>this._observerCallback(ti),ei)}_observerCallback(ei){let ti=si=>this._targetLinks.get(`#${si.target.id}`),ni=si=>{this._previousScrollData.visibleEntryTop=si.target.offsetTop,this._process(ti(si))},ri=(this._rootElement||document.documentElement).scrollTop,oi=ri>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=ri;for(let si of ei){if(!si.isIntersecting){this._activeTarget=null,this._clearActiveClass(ti(si));continue}let ai=si.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(oi&&ai){if(ni(si),!ri)return;continue}!oi&&!ai&&ni(si)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;let ei=Wi.find(uc,this._config.target);for(let ti of ei){if(!ti.hash||Do(ti))continue;let ni=Wi.findOne(decodeURI(ti.hash),this._element);As(ni)&&(this._targetLinks.set(decodeURI(ti.hash),ti),this._observableSections.set(ti.hash,ni))}}_process(ei){this._activeTarget!==ei&&(this._clearActiveClass(this._config.target),this._activeTarget=ei,ei.classList.add(ws),this._activateParents(ei),wi.trigger(this._element,ty,{relatedTarget:ei}))}_activateParents(ei){if(ei.classList.contains(ny)){Wi.findOne(uy,ei.closest(cy)).classList.add(ws);return}for(let ti of Wi.parents(ei,oy))for(let ni of Wi.prev(ti,ly))ni.classList.add(ws)}_clearActiveClass(ei){ei.classList.remove(ws);let ti=Wi.find(`${uc}.${ws}`,ei);for(let ni of ti)ni.classList.remove(ws)}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(ti[ei]===void 0||ei.startsWith("_")||ei==="constructor")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}};wi.on(window,iy,()=>{for(let ii of Wi.find(ry))Za.getOrCreateInstance(ii)});Qr(Za);var hy="tab",py="bs.tab",ns=`.${py}`,my=`hide${ns}`,gy=`hidden${ns}`,vy=`show${ns}`,yy=`shown${ns}`,by=`click${ns}`,_y=`keydown${ns}`,Ey=`load${ns}`,wy="ArrowLeft",Ju="ArrowRight",xy="ArrowUp",Zu="ArrowDown",dc="Home",ed="End",Zo="active",td="fade",fc="show",Ty="dropdown",Dd=".dropdown-toggle",Cy=".dropdown-menu",hc=`:not(${Dd})`,Sy='.list-group, .nav, [role="tablist"]',Ay=".nav-item, .list-group-item",Dy=`.nav-link${hc}, .list-group-item${hc}, [role="tab"]${hc}`,Od='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',pc=`${Dy}, ${Od}`,Oy=`.${Zo}[data-bs-toggle="tab"], .${Zo}[data-bs-toggle="pill"], .${Zo}[data-bs-toggle="list"]`,ts=class ii extends Qn{constructor(ei){super(ei),this._parent=this._element.closest(Sy),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),wi.on(this._element,_y,ti=>this._keydown(ti)))}static get NAME(){return hy}show(){let ei=this._element;if(this._elemIsActive(ei))return;let ti=this._getActiveElem(),ni=ti?wi.trigger(ti,my,{relatedTarget:ei}):null;wi.trigger(ei,vy,{relatedTarget:ti}).defaultPrevented||ni&&ni.defaultPrevented||(this._deactivate(ti,ei),this._activate(ei,ti))}_activate(ei,ti){if(!ei)return;ei.classList.add(Zo),this._activate(Wi.getElementFromSelector(ei));let ni=()=>{if(ei.getAttribute("role")!=="tab"){ei.classList.add(fc);return}ei.removeAttribute("tabindex"),ei.setAttribute("aria-selected",!0),this._toggleDropDown(ei,!0),wi.trigger(ei,yy,{relatedTarget:ti})};this._queueCallback(ni,ei,ei.classList.contains(td))}_deactivate(ei,ti){if(!ei)return;ei.classList.remove(Zo),ei.blur(),this._deactivate(Wi.getElementFromSelector(ei));let ni=()=>{if(ei.getAttribute("role")!=="tab"){ei.classList.remove(fc);return}ei.setAttribute("aria-selected",!1),ei.setAttribute("tabindex","-1"),this._toggleDropDown(ei,!1),wi.trigger(ei,gy,{relatedTarget:ti})};this._queueCallback(ni,ei,ei.classList.contains(td))}_keydown(ei){if(![wy,Ju,xy,Zu,dc,ed].includes(ei.key))return;ei.stopPropagation(),ei.preventDefault();let ti=this._getChildren().filter(ri=>!Do(ri)),ni;if([dc,ed].includes(ei.key))ni=ti[ei.key===dc?0:ti.length-1];else{let ri=[Ju,Zu].includes(ei.key);ni=bc(ti,ei.target,ri,!0)}ni&&(ni.focus({preventScroll:!0}),ii.getOrCreateInstance(ni).show())}_getChildren(){return Wi.find(pc,this._parent)}_getActiveElem(){return this._getChildren().find(ei=>this._elemIsActive(ei))||null}_setInitialAttributes(ei,ti){this._setAttributeIfNotExists(ei,"role","tablist");for(let ni of ti)this._setInitialAttributesOnChild(ni)}_setInitialAttributesOnChild(ei){ei=this._getInnerElement(ei);let ti=this._elemIsActive(ei),ni=this._getOuterElement(ei);ei.setAttribute("aria-selected",ti),ni!==ei&&this._setAttributeIfNotExists(ni,"role","presentation"),ti||ei.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(ei,"role","tab"),this._setInitialAttributesOnTargetPanel(ei)}_setInitialAttributesOnTargetPanel(ei){let ti=Wi.getElementFromSelector(ei);ti&&(this._setAttributeIfNotExists(ti,"role","tabpanel"),ei.id&&this._setAttributeIfNotExists(ti,"aria-labelledby",`${ei.id}`))}_toggleDropDown(ei,ti){let ni=this._getOuterElement(ei);if(!ni.classList.contains(Ty))return;let ri=(oi,si)=>{let ai=Wi.findOne(oi,ni);ai&&ai.classList.toggle(si,ti)};ri(Dd,Zo),ri(Cy,fc),ni.setAttribute("aria-expanded",ti)}_setAttributeIfNotExists(ei,ti,ni){ei.hasAttribute(ti)||ei.setAttribute(ti,ni)}_elemIsActive(ei){return ei.classList.contains(Zo)}_getInnerElement(ei){return ei.matches(pc)?ei:Wi.findOne(pc,ei)}_getOuterElement(ei){return ei.closest(Ay)||ei}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this);if(typeof ei=="string"){if(ti[ei]===void 0||ei.startsWith("_")||ei==="constructor")throw new TypeError(`No method named "${ei}"`);ti[ei]()}})}};wi.on(document,by,Od,function(ii){["A","AREA"].includes(this.tagName)&&ii.preventDefault(),!Do(this)&&ts.getOrCreateInstance(this).show()});wi.on(window,Ey,()=>{for(let ii of Wi.find(Oy))ts.getOrCreateInstance(ii)});Qr(ts);var Ly="toast",My="bs.toast",No=`.${My}`,ky=`mouseover${No}`,Ny=`mouseout${No}`,Ry=`focusin${No}`,Iy=`focusout${No}`,Hy=`hide${No}`,Py=`hidden${No}`,Fy=`show${No}`,$y=`shown${No}`,By="fade",id="hide",Va="show",ja="showing",zy={animation:"boolean",autohide:"boolean",delay:"number"},Vy={animation:!0,autohide:!0,delay:5e3},vo=class ii extends Qn{constructor(ei,ti){super(ei,ti),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Vy}static get DefaultType(){return zy}static get NAME(){return Ly}show(){if(wi.trigger(this._element,Fy).defaultPrevented)return;this._clearTimeout(),this._config.animation&&this._element.classList.add(By);let ti=()=>{this._element.classList.remove(ja),wi.trigger(this._element,$y),this._maybeScheduleHide()};this._element.classList.remove(id),na(this._element),this._element.classList.add(Va,ja),this._queueCallback(ti,this._element,this._config.animation)}hide(){if(!this.isShown()||wi.trigger(this._element,Hy).defaultPrevented)return;let ti=()=>{this._element.classList.add(id),this._element.classList.remove(ja,Va),wi.trigger(this._element,Py)};this._element.classList.add(ja),this._queueCallback(ti,this._element,this._config.animation)}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(Va),super.dispose()}isShown(){return this._element.classList.contains(Va)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(ei,ti){switch(ei.type){case"mouseover":case"mouseout":{this._hasMouseInteraction=ti;break}case"focusin":case"focusout":{this._hasKeyboardInteraction=ti;break}}if(ti){this._clearTimeout();return}let ni=ei.relatedTarget;this._element===ni||this._element.contains(ni)||this._maybeScheduleHide()}_setListeners(){wi.on(this._element,ky,ei=>this._onInteraction(ei,!0)),wi.on(this._element,Ny,ei=>this._onInteraction(ei,!1)),wi.on(this._element,Ry,ei=>this._onInteraction(ei,!0)),wi.on(this._element,Iy,ei=>this._onInteraction(ei,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(ei){return this.each(function(){let ti=ii.getOrCreateInstance(this,ei);if(typeof ei=="string"){if(typeof ti[ei]=="undefined")throw new TypeError(`No method named "${ei}"`);ti[ei](this)}})}};el(vo);Qr(vo);var FL=cu(Ld());function xc(ii,ei){ii.split(/\s+/).forEach(ti=>{ei(ti)})}var oa=class{constructor(){this._events={}}on(ei,ti){xc(ei,ni=>{let ri=this._events[ni]||[];ri.push(ti),this._events[ni]=ri})}off(ei,ti){var ni=arguments.length;if(ni===0){this._events={};return}xc(ei,ri=>{if(ni===1){delete this._events[ri];return}let oi=this._events[ri];oi!==void 0&&(oi.splice(oi.indexOf(ti),1),this._events[ri]=oi)})}trigger(ei,...ti){var ni=this;xc(ei,ri=>{let oi=ni._events[ri];oi!==void 0&&oi.forEach(si=>{si.apply(ni,ti)})})}};function Tc(ii){return ii.plugins={},class extends ii{constructor(){super(...arguments),this.plugins={names:[],settings:{},requested:{},loaded:{}}}static define(ei,ti){ii.plugins[ei]={name:ei,fn:ti}}initializePlugins(ei){var ti,ni;let ri=this,oi=[];if(Array.isArray(ei))ei.forEach(si=>{typeof si=="string"?oi.push(si):(ri.plugins.settings[si.name]=si.options,oi.push(si.name))});else if(ei)for(ti in ei)ei.hasOwnProperty(ti)&&(ri.plugins.settings[ti]=ei[ti],oi.push(ti));for(;ni=oi.shift();)ri.require(ni)}loadPlugin(ei){var ti=this,ni=ti.plugins,ri=ii.plugins[ei];if(!ii.plugins.hasOwnProperty(ei))throw new Error('Unable to find "'+ei+'" plugin');ni.requested[ei]=!0,ni.loaded[ei]=ri.fn.apply(ti,[ti.plugins.settings[ei]||{}]),ni.names.push(ei)}require(ei){var ti=this,ni=ti.plugins;if(!ti.plugins.loaded.hasOwnProperty(ei)){if(ni.requested[ei])throw new Error('Plugin has circular dependency ("'+ei+'")');ti.loadPlugin(ei)}return ni.loaded[ei]}}}var sa=ii=>(ii=ii.filter(Boolean),ii.length<2?ii[0]||"":qy(ii)==1?"["+ii.join("")+"]":"(?:"+ii.join("|")+")"),Cc=ii=>{if(!jy(ii))return ii.join("");let ei="",ti=0,ni=()=>{ti>1&&(ei+="{"+ti+"}")};return ii.forEach((ri,oi)=>{if(ri===ii[oi-1]){ti++;return}ni(),ei+=ri,ti=1}),ni(),ei},Sc=ii=>{let ei=Array.from(ii);return sa(ei)},jy=ii=>new Set(ii).size!==ii.length,Ro=ii=>(ii+"").replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu,"\\$1"),qy=ii=>ii.reduce((ei,ti)=>Math.max(ei,Wy(ti)),0),Wy=ii=>Array.from(ii).length;var Ac=ii=>{if(ii.length===1)return[[ii]];let ei=[],ti=ii.substring(1);return Ac(ti).forEach(function(ri){let oi=ri.slice(0);oi[0]=ii.charAt(0)+oi[0],ei.push(oi),oi=ri.slice(0),oi.unshift(ii.charAt(0)),ei.push(oi)}),ei};var Uy=[[0,65535]],Yy="[\u0300-\u036F\xB7\u02BE\u02BC]",tl,Rd,Gy=3,Dc={},Md={"/":"\u2044\u2215",0:"\u07C0",a:"\u2C65\u0250\u0251",aa:"\uA733",ae:"\xE6\u01FD\u01E3",ao:"\uA735",au:"\uA737",av:"\uA739\uA73B",ay:"\uA73D",b:"\u0180\u0253\u0183",c:"\uA73F\u0188\u023C\u2184",d:"\u0111\u0257\u0256\u1D05\u018C\uABB7\u0501\u0266",e:"\u025B\u01DD\u1D07\u0247",f:"\uA77C\u0192",g:"\u01E5\u0260\uA7A1\u1D79\uA77F\u0262",h:"\u0127\u2C68\u2C76\u0265",i:"\u0268\u0131",j:"\u0249\u0237",k:"\u0199\u2C6A\uA741\uA743\uA745\uA7A3",l:"\u0142\u019A\u026B\u2C61\uA749\uA747\uA781\u026D",m:"\u0271\u026F\u03FB",n:"\uA7A5\u019E\u0272\uA791\u1D0E\u043B\u0509",o:"\xF8\u01FF\u0254\u0275\uA74B\uA74D\u1D11",oe:"\u0153",oi:"\u01A3",oo:"\uA74F",ou:"\u0223",p:"\u01A5\u1D7D\uA751\uA753\uA755\u03C1",q:"\uA757\uA759\u024B",r:"\u024D\u027D\uA75B\uA7A7\uA783",s:"\xDF\u023F\uA7A9\uA785\u0282",t:"\u0167\u01AD\u0288\u2C66\uA787",th:"\xFE",tz:"\uA729",u:"\u0289",v:"\u028B\uA75F\u028C",vy:"\uA761",w:"\u2C73",y:"\u01B4\u024F\u1EFF",z:"\u01B6\u0225\u0240\u2C6C\uA763",hv:"\u0195"};for(let ii in Md){let ei=Md[ii]||"";for(let ti=0;ti{tl===void 0&&(tl=eb(ii||Uy))},kd=(ii,ei="NFKD")=>ii.normalize(ei),aa=ii=>Array.from(ii).reduce((ei,ti)=>ei+Xy(ti),""),Xy=ii=>(ii=kd(ii).toLowerCase().replace(Ky,ei=>Dc[ei]||""),kd(ii,"NFC"));function*Jy(ii){for(let[ei,ti]of ii)for(let ni=ei;ni<=ti;ni++){let ri=String.fromCharCode(ni),oi=aa(ri);oi!=ri.toLowerCase()&&(oi.length>Gy||oi.length!=0&&(yield{folded:oi,composed:ri,code_point:ni}))}}var Zy=ii=>{let ei={},ti=(ni,ri)=>{let oi=ei[ni]||new Set,si=new RegExp("^"+Sc(oi)+"$","iu");ri.match(si)||(oi.add(Ro(ri)),ei[ni]=oi)};for(let ni of Jy(ii))ti(ni.folded,ni.folded),ti(ni.folded,ni.composed);return ei},eb=ii=>{let ei=Zy(ii),ti={},ni=[];for(let oi in ei){let si=ei[oi];si&&(ti[oi]=Sc(si)),oi.length>1&&ni.push(Ro(oi))}ni.sort((oi,si)=>si.length-oi.length);let ri=sa(ni);return Rd=new RegExp("^"+ri,"u"),ti},tb=(ii,ei=1)=>{let ti=0;return ii=ii.map(ni=>(tl[ni]&&(ti+=ni.length),tl[ni]||ni)),ti>=ei?Cc(ii):""},ib=(ii,ei=1)=>(ei=Math.max(ei,ii.length-1),sa(Ac(ii).map(ti=>tb(ti,ei)))),Nd=(ii,ei=!0)=>{let ti=ii.length>1?1:0;return sa(ii.map(ni=>{let ri=[],oi=ei?ni.length():ni.length()-1;for(let si=0;si{for(let ti of ei){if(ti.start!=ii.start||ti.end!=ii.end||ti.substrs.join("")!==ii.substrs.join(""))continue;let ni=ii.parts,ri=si=>{for(let ai of ni){if(ai.start===si.start&&ai.substr===si.substr)return!1;if(!(si.length==1||ai.length==1)&&(si.startai.start||ai.startsi.start))return!0}return!1};if(!(ti.parts.filter(ri).length>0))return!0}return!1},il=class ii{constructor(){en(this,"parts");en(this,"substrs");en(this,"start");en(this,"end");this.parts=[],this.substrs=[],this.start=0,this.end=0}add(ei){ei&&(this.parts.push(ei),this.substrs.push(ei.substr),this.start=Math.min(ei.start,this.start),this.end=Math.max(ei.end,this.end))}last(){return this.parts[this.parts.length-1]}length(){return this.parts.length}clone(ei,ti){let ni=new ii,ri=JSON.parse(JSON.stringify(this.parts)),oi=ri.pop();for(let li of ri)ni.add(li);let si=ti.substr.substring(0,ei-oi.start),ai=si.length;return ni.add({start:oi.start,end:oi.start+ai,length:ai,substr:si}),ni}},Id=ii=>{Qy(),ii=aa(ii);let ei="",ti=[new il];for(let ni=0;ni0){li=li.sort((ci,di)=>ci.length()-di.length());for(let ci of li)nb(ci,ti)||ti.push(ci);continue}if(ni>0&&ui.size==1&&!ui.has("3")){ei+=Nd(ti,!1);let ci=new il,di=ti[0];di&&ci.add(di.last()),ti=[ci]}}return ei+=Nd(ti,!0),ei};var Hd=(ii,ei)=>{if(ii)return ii[ei]},Pd=(ii,ei)=>{if(ii){for(var ti,ni=ei.split(".");(ti=ni.shift())&&(ii=ii[ti]););return ii}},nl=(ii,ei,ti)=>{var ni,ri;return!ii||(ii=ii+"",ei.regex==null)||(ri=ii.search(ei.regex),ri===-1)?0:(ni=ei.string.length/ii.length,ri===0&&(ni+=.5),ni*ti)},rl=(ii,ei)=>{var ti=ii[ei];if(typeof ti=="function")return ti;ti&&!Array.isArray(ti)&&(ii[ei]=[ti])},la=(ii,ei)=>{if(Array.isArray(ii))ii.forEach(ei);else for(var ti in ii)ii.hasOwnProperty(ti)&&ei(ii[ti],ti)},Fd=(ii,ei)=>typeof ii=="number"&&typeof ei=="number"?ii>ei?1:iiei?1:ei>ii?-1:0);var ol=class{constructor(ei,ti){en(this,"items");en(this,"settings");this.items=ei,this.settings=ti||{diacritics:!0}}tokenize(ei,ti,ni){if(!ei||!ei.length)return[];let ri=[],oi=ei.split(/\s+/);var si;return ni&&(si=new RegExp("^("+Object.keys(ni).map(Ro).join("|")+"):(.*)$")),oi.forEach(ai=>{let li,ui=null,ci=null;si&&(li=ai.match(si))&&(ui=li[1],ai=li[2]),ai.length>0&&(this.settings.diacritics?ci=Id(ai)||null:ci=Ro(ai),ci&&ti&&(ci="\\b"+ci)),ri.push({string:ai,regex:ci?new RegExp(ci,"iu"):null,field:ui})}),ri}getScoreFunction(ei,ti){var ni=this.prepareSearch(ei,ti);return this._getScoreFunction(ni)}_getScoreFunction(ei){let ti=ei.tokens,ni=ti.length;if(!ni)return function(){return 0};let ri=ei.options.fields,oi=ei.weights,si=ri.length,ai=ei.getAttrFn;if(!si)return function(){return 1};let li=function(){return si===1?function(ui,ci){let di=ri[0].field;return nl(ai(ci,di),ui,oi[di]||1)}:function(ui,ci){var di=0;if(ui.field){let pi=ai(ci,ui.field);!ui.regex&&pi?di+=1/si:di+=nl(pi,ui,1)}else la(oi,(pi,yi)=>{di+=nl(ai(ci,yi),ui,pi)});return di/si}}();return ni===1?function(ui){return li(ti[0],ui)}:ei.options.conjunction==="and"?function(ui){var ci,di=0;for(let pi of ti){if(ci=li(pi,ui),ci<=0)return 0;di+=ci}return di/ni}:function(ui){var ci=0;return la(ti,di=>{ci+=li(di,ui)}),ci/ni}}getSortFunction(ei,ti){var ni=this.prepareSearch(ei,ti);return this._getSortFunction(ni)}_getSortFunction(ei){var ti,ni=[];let ri=this,oi=ei.options,si=!ei.query&&oi.sort_empty?oi.sort_empty:oi.sort;if(typeof si=="function")return si.bind(this);let ai=function(ui,ci){return ui==="$score"?ci.score:ei.getAttrFn(ri.items[ci.id],ui)};if(si)for(let ui of si)(ei.query||ui.field!=="$score")&&ni.push(ui);if(ei.query){ti=!0;for(let ui of ni)if(ui.field==="$score"){ti=!1;break}ti&&ni.unshift({field:"$score",direction:"desc"})}else ni=ni.filter(ui=>ui.field!=="$score");return ni.length?function(ui,ci){var di,pi;for(let yi of ni)if(pi=yi.field,di=(yi.direction==="desc"?-1:1)*Fd(ai(pi,ui),ai(pi,ci)),di)return di;return 0}:null}prepareSearch(ei,ti){let ni={};var ri=Object.assign({},ti);if(rl(ri,"sort"),rl(ri,"sort_empty"),ri.fields){rl(ri,"fields");let oi=[];ri.fields.forEach(si=>{typeof si=="string"&&(si={field:si,weight:1}),oi.push(si),ni[si.field]="weight"in si?si.weight:1}),ri.fields=oi}return{options:ri,query:ei.toLowerCase().trim(),tokens:this.tokenize(ei,ri.respect_word_boundaries,ni),total:0,items:[],weights:ni,getAttrFn:ri.nesting?Pd:Hd}}search(ei,ti){var ni=this,ri,oi;oi=this.prepareSearch(ei,ti),ti=oi.options,ei=oi.query;let si=ti.score||ni._getScoreFunction(oi);ei.length?la(ni.items,(li,ui)=>{ri=si(li),(ti.filter===!1||ri>0)&&oi.items.push({score:ri,id:ui})}):la(ni.items,(li,ui)=>{oi.items.push({score:1,id:ui})});let ai=ni._getSortFunction(oi);return ai&&oi.items.sort(ai),oi.total=oi.items.length,typeof ti.limit=="number"&&(oi.items=oi.items.slice(0,ti.limit)),oi}};var Xn=ii=>typeof ii=="undefined"||ii===null?null:ca(ii),ca=ii=>typeof ii=="boolean"?ii?"1":"0":ii+"",sl=ii=>(ii+"").replace(/&/g,"&").replace(//g,">").replace(/"/g,"""),$d=(ii,ei)=>ei>0?window.setTimeout(ii,ei):(ii.call(null),null),Bd=(ii,ei)=>{var ti;return function(ni,ri){var oi=this;ti&&(oi.loading=Math.max(oi.loading-1,0),clearTimeout(ti)),ti=setTimeout(function(){ti=null,oi.loadedSearches[ni]=!0,ii.call(oi,ni,ri)},ei)}},Oc=(ii,ei,ti)=>{var ni,ri=ii.trigger,oi={};ii.trigger=function(){var si=arguments[0];if(ei.indexOf(si)!==-1)oi[si]=arguments;else return ri.apply(ii,arguments)},ti.apply(ii,[]),ii.trigger=ri;for(ni of ei)ni in oi&&ri.apply(ii,oi[ni])},zd=ii=>({start:ii.selectionStart||0,length:(ii.selectionEnd||0)-(ii.selectionStart||0)}),fn=(ii,ei=!1)=>{ii&&(ii.preventDefault(),ei&&ii.stopPropagation())},Nn=(ii,ei,ti,ni)=>{ii.addEventListener(ei,ti,ni)},Io=(ii,ei)=>{if(!ei||!ei[ii])return!1;var ti=(ei.altKey?1:0)+(ei.ctrlKey?1:0)+(ei.shiftKey?1:0)+(ei.metaKey?1:0);return ti===1},al=(ii,ei)=>{let ti=ii.getAttribute("id");return ti||(ii.setAttribute("id",ei),ei)},Lc=ii=>ii.replace(/[\\"']/g,"\\$&"),Ho=(ii,ei)=>{ei&&ii.append(ei)},En=(ii,ei)=>{if(Array.isArray(ii))ii.forEach(ei);else for(var ti in ii)ii.hasOwnProperty(ti)&&ei(ii[ti],ti)};var no=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(Mc(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},Mc=ii=>typeof ii=="string"&&ii.indexOf("<")>-1,Vd=ii=>ii.replace(/['"\\]/g,"\\$&"),ll=(ii,ei)=>{var ti=document.createEvent("HTMLEvents");ti.initEvent(ei,!0,!1),ii.dispatchEvent(ti)},ua=(ii,ei)=>{Object.assign(ii.style,ei)},jn=(ii,...ei)=>{var ti=jd(ei);ii=qd(ii),ii.map(ni=>{ti.map(ri=>{ni.classList.add(ri)})})},bo=(ii,...ei)=>{var ti=jd(ei);ii=qd(ii),ii.map(ni=>{ti.map(ri=>{ni.classList.remove(ri)})})},jd=ii=>{var ei=[];return En(ii,ti=>{typeof ti=="string"&&(ti=ti.trim().split(/[\t\n\f\r\s]/)),Array.isArray(ti)&&(ei=ei.concat(ti))}),ei.filter(Boolean)},qd=ii=>(Array.isArray(ii)||(ii=[ii]),ii),cl=(ii,ei,ti)=>{if(!(ti&&!ti.contains(ii)))for(;ii&&ii.matches;){if(ii.matches(ei))return ii;ii=ii.parentNode}},kc=(ii,ei=0)=>ei>0?ii[ii.length-1]:ii[0],Wd=ii=>Object.keys(ii).length===0,Nc=(ii,ei)=>{if(!ii)return-1;ei=ei||ii.nodeName;for(var ti=0;ii=ii.previousElementSibling;)ii.matches(ei)&&ti++;return ti},an=(ii,ei)=>{En(ei,(ti,ni)=>{ti==null?ii.removeAttribute(ni):ii.setAttribute(ni,""+ti)})},da=(ii,ei)=>{ii.parentNode&&ii.parentNode.replaceChild(ei,ii)};var Ud=(ii,ei)=>{if(ei===null)return;if(typeof ei=="string"){if(!ei.length)return;ei=new RegExp(ei,"i")}let ti=oi=>{var si=oi.data.match(ei);if(si&&oi.data.length>0){var ai=document.createElement("span");ai.className="highlight";var li=oi.splitText(si.index);li.splitText(si[0].length);var ui=li.cloneNode(!0);return ai.appendChild(ui),da(li,ai),1}return 0},ni=oi=>{oi.nodeType===1&&oi.childNodes&&!/(script|style)/i.test(oi.tagName)&&(oi.className!=="highlight"||oi.tagName!=="SPAN")&&Array.from(oi.childNodes).forEach(si=>{ri(si)})},ri=oi=>oi.nodeType===3?ti(oi):(ni(oi),0);ri(ii)},Yd=ii=>{var ei=ii.querySelectorAll("span.highlight");Array.prototype.forEach.call(ei,function(ti){var ni=ti.parentNode;ni.replaceChild(ti.firstChild,ti),ni.normalize()})};var rb=typeof navigator=="undefined"?!1:/Mac/.test(navigator.userAgent),fa=rb?"metaKey":"ctrlKey";var Rc={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:null,createOnBlur:!1,createFilter:null,highlight:!0,openOnFocus:!0,shouldOpen:null,maxOptions:50,maxItems:null,hideSelected:null,duplicates:!1,addPrecedence:!1,selectOnTab:!1,preload:null,allowEmptyOption:!1,refreshThrottle:300,loadThrottle:300,loadingClass:"loading",dataAttr:null,optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"ts-wrapper",controlClass:"ts-control",dropdownClass:"ts-dropdown",dropdownContentClass:"ts-dropdown-content",itemClass:"item",optionClass:"option",dropdownParent:null,controlInput:'',copyClassesToDropdown:!1,placeholder:null,hidePlaceholder:null,shouldLoad:function(ii){return ii.length>0},render:{}};function ul(ii,ei){var ti=Object.assign({},Rc,ei),ni=ti.dataAttr,ri=ti.labelField,oi=ti.valueField,si=ti.disabledField,ai=ti.optgroupField,li=ti.optgroupLabelField,ui=ti.optgroupValueField,ci=ii.tagName.toLowerCase(),di=ii.getAttribute("placeholder")||ii.getAttribute("data-placeholder");if(!di&&!ti.allowEmptyOption){let vi=ii.querySelector('option[value=""]');vi&&(di=vi.textContent)}var pi={placeholder:di,options:[],optgroups:[],items:[],maxItems:null},yi=()=>{var vi,Ei=pi.options,Si={},xi=1;let Li=0;var Oi=ki=>{var Mi=Object.assign({},ki.dataset),Ai=ni&&Mi[ni];return typeof Ai=="string"&&Ai.length&&(Mi=Object.assign(Mi,JSON.parse(Ai))),Mi},zi=(ki,Mi)=>{var Ai=Xn(ki.value);if(Ai!=null&&!(!Ai&&!ti.allowEmptyOption)){if(Si.hasOwnProperty(Ai)){if(Mi){var qi=Si[Ai][ai];qi?Array.isArray(qi)?qi.push(Mi):Si[Ai][ai]=[qi,Mi]:Si[Ai][ai]=Mi}}else{var Ci=Oi(ki);Ci[ri]=Ci[ri]||ki.textContent,Ci[oi]=Ci[oi]||Ai,Ci[si]=Ci[si]||ki.disabled,Ci[ai]=Ci[ai]||Mi,Ci.$option=ki,Ci.$order=Ci.$order||++Li,Si[Ai]=Ci,Ei.push(Ci)}ki.selected&&pi.items.push(Ai)}},Vi=ki=>{var Mi,Ai;Ai=Oi(ki),Ai[li]=Ai[li]||ki.getAttribute("label")||"",Ai[ui]=Ai[ui]||xi++,Ai[si]=Ai[si]||ki.disabled,Ai.$order=Ai.$order||++Li,pi.optgroups.push(Ai),Mi=Ai[ui],En(ki.children,qi=>{zi(qi,Mi)})};pi.maxItems=ii.hasAttribute("multiple")?null:1,En(ii.children,ki=>{vi=ki.tagName.toLowerCase(),vi==="optgroup"?Vi(ki):vi==="option"&&zi(ki)})},gi=()=>{let vi=ii.getAttribute(ni);if(vi)pi.options=JSON.parse(vi),En(pi.options,Si=>{pi.items.push(Si[oi])});else{var Ei=ii.value.trim()||"";if(!ti.allowEmptyOption&&!Ei.length)return;let Si=Ei.split(ti.delimiter);En(Si,xi=>{let Li={};Li[ri]=xi,Li[oi]=xi,pi.options.push(Li)}),pi.items=Si}};return ci==="select"?yi():gi(),Object.assign({},Rc,pi,ei)}var Qd=0,Cn=class extends Tc(oa){constructor(ei,ti){super(),this.order=0,this.isOpen=!1,this.isDisabled=!1,this.isReadOnly=!1,this.isInvalid=!1,this.isValid=!0,this.isLocked=!1,this.isFocused=!1,this.isInputHidden=!1,this.isSetup=!1,this.ignoreFocus=!1,this.ignoreHover=!1,this.hasOptions=!1,this.lastValue="",this.caretPos=0,this.loading=0,this.loadedSearches={},this.activeOption=null,this.activeItems=[],this.optgroups={},this.options={},this.userOptions={},this.items=[],this.refreshTimeout=null,Qd++;var ni,ri=no(ei);if(ri.tomselect)throw new Error("Tom Select already initialized on this element");ri.tomselect=this;var oi=window.getComputedStyle&&window.getComputedStyle(ri,null);ni=oi.getPropertyValue("direction");let si=ul(ri,ti);this.settings=si,this.input=ri,this.tabIndex=ri.tabIndex||0,this.is_select_tag=ri.tagName.toLowerCase()==="select",this.rtl=/rtl/i.test(ni),this.inputId=al(ri,"tomselect-"+Qd),this.isRequired=ri.required,this.sifter=new ol(this.options,{diacritics:si.diacritics}),si.mode=si.mode||(si.maxItems===1?"single":"multi"),typeof si.hideSelected!="boolean"&&(si.hideSelected=si.mode==="multi"),typeof si.hidePlaceholder!="boolean"&&(si.hidePlaceholder=si.mode!=="multi");var ai=si.createFilter;typeof ai!="function"&&(typeof ai=="string"&&(ai=new RegExp(ai)),ai instanceof RegExp?si.createFilter=Ei=>ai.test(Ei):si.createFilter=Ei=>this.settings.duplicates||!this.options[Ei]),this.initializePlugins(si.plugins),this.setupCallbacks(),this.setupTemplates();let li=no("
"),ui=no("
"),ci=this._render("dropdown"),di=no('
'),pi=this.input.getAttribute("class")||"",yi=si.mode;var gi;if(jn(li,si.wrapperClass,pi,yi),jn(ui,si.controlClass),Ho(li,ui),jn(ci,si.dropdownClass,yi),si.copyClassesToDropdown&&jn(ci,pi),jn(di,si.dropdownContentClass),Ho(ci,di),no(si.dropdownParent||li).appendChild(ci),Mc(si.controlInput)){gi=no(si.controlInput);var vi=["autocorrect","autocapitalize","autocomplete","spellcheck"];En(vi,Ei=>{ri.getAttribute(Ei)&&an(gi,{[Ei]:ri.getAttribute(Ei)})}),gi.tabIndex=-1,ui.appendChild(gi),this.focus_node=gi}else si.controlInput?(gi=no(si.controlInput),this.focus_node=gi):(gi=no(""),this.focus_node=ui);this.wrapper=li,this.dropdown=ci,this.dropdown_content=di,this.control=ui,this.control_input=gi,this.setup()}setup(){let ei=this,ti=ei.settings,ni=ei.control_input,ri=ei.dropdown,oi=ei.dropdown_content,si=ei.wrapper,ai=ei.control,li=ei.input,ui=ei.focus_node,ci={passive:!0},di=ei.inputId+"-ts-dropdown";an(oi,{id:di}),an(ui,{role:"combobox","aria-haspopup":"listbox","aria-expanded":"false","aria-controls":di});let pi=al(ui,ei.inputId+"-ts-control"),yi="label[for='"+Vd(ei.inputId)+"']",gi=document.querySelector(yi),vi=ei.focus.bind(ei);if(gi){Nn(gi,"click",vi),an(gi,{for:pi});let xi=al(gi,ei.inputId+"-ts-label");an(ui,{"aria-labelledby":xi}),an(oi,{"aria-labelledby":xi})}if(si.style.width=li.style.width,ei.plugins.names.length){let xi="plugin-"+ei.plugins.names.join(" plugin-");jn([si,ri],xi)}(ti.maxItems===null||ti.maxItems>1)&&ei.is_select_tag&&an(li,{multiple:"multiple"}),ti.placeholder&&an(ni,{placeholder:ti.placeholder}),!ti.splitOn&&ti.delimiter&&(ti.splitOn=new RegExp("\\s*"+Ro(ti.delimiter)+"+\\s*")),ti.load&&ti.loadThrottle&&(ti.load=Bd(ti.load,ti.loadThrottle)),Nn(ri,"mousemove",()=>{ei.ignoreHover=!1}),Nn(ri,"mouseenter",xi=>{var Li=cl(xi.target,"[data-selectable]",ri);Li&&ei.onOptionHover(xi,Li)},{capture:!0}),Nn(ri,"click",xi=>{let Li=cl(xi.target,"[data-selectable]");Li&&(ei.onOptionSelect(xi,Li),fn(xi,!0))}),Nn(ai,"click",xi=>{var Li=cl(xi.target,"[data-ts-item]",ai);if(Li&&ei.onItemSelect(xi,Li)){fn(xi,!0);return}ni.value==""&&(ei.onClick(),fn(xi,!0))}),Nn(ui,"keydown",xi=>ei.onKeyDown(xi)),Nn(ni,"keypress",xi=>ei.onKeyPress(xi)),Nn(ni,"input",xi=>ei.onInput(xi)),Nn(ui,"blur",xi=>ei.onBlur(xi)),Nn(ui,"focus",xi=>ei.onFocus(xi)),Nn(ni,"paste",xi=>ei.onPaste(xi));let Ei=xi=>{let Li=xi.composedPath()[0];if(!si.contains(Li)&&!ri.contains(Li)){ei.isFocused&&ei.blur(),ei.inputState();return}Li==ni&&ei.isOpen?xi.stopPropagation():fn(xi,!0)},Si=()=>{ei.isOpen&&ei.positionDropdown()};Nn(document,"mousedown",Ei),Nn(window,"scroll",Si,ci),Nn(window,"resize",Si,ci),this._destroy=()=>{document.removeEventListener("mousedown",Ei),window.removeEventListener("scroll",Si),window.removeEventListener("resize",Si),gi&&gi.removeEventListener("click",vi)},this.revertSettings={innerHTML:li.innerHTML,tabIndex:li.tabIndex},li.tabIndex=-1,li.insertAdjacentElement("afterend",ei.wrapper),ei.sync(!1),ti.items=[],delete ti.optgroups,delete ti.options,Nn(li,"invalid",()=>{ei.isValid&&(ei.isValid=!1,ei.isInvalid=!0,ei.refreshState())}),ei.updateOriginalInput(),ei.refreshItems(),ei.close(!1),ei.inputState(),ei.isSetup=!0,li.disabled?ei.disable():li.readOnly?ei.setReadOnly(!0):ei.enable(),ei.on("change",this.onChange),jn(li,"tomselected","ts-hidden-accessible"),ei.trigger("initialize"),ti.preload===!0&&ei.preload()}setupOptions(ei=[],ti=[]){this.addOptions(ei),En(ti,ni=>{this.registerOptionGroup(ni)})}setupTemplates(){var ei=this,ti=ei.settings.labelField,ni=ei.settings.optgroupLabelField,ri={optgroup:oi=>{let si=document.createElement("div");return si.className="optgroup",si.appendChild(oi.options),si},optgroup_header:(oi,si)=>'
'+si(oi[ni])+"
",option:(oi,si)=>"
"+si(oi[ti])+"
",item:(oi,si)=>"
"+si(oi[ti])+"
",option_create:(oi,si)=>'
Add '+si(oi.input)+"
",no_results:()=>'
No results found
',loading:()=>'
',not_loading:()=>{},dropdown:()=>"
"};ei.settings.render=Object.assign({},ri,ei.settings.render)}setupCallbacks(){var ei,ti,ni={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",item_select:"onItemSelect",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(ei in ni)ti=this.settings[ni[ei]],ti&&this.on(ei,ti)}sync(ei=!0){let ti=this,ni=ei?ul(ti.input,{delimiter:ti.settings.delimiter}):ti.settings;ti.setupOptions(ni.options,ni.optgroups),ti.setValue(ni.items||[],!0),ti.lastQuery=null}onClick(){var ei=this;if(ei.activeItems.length>0){ei.clearActiveItems(),ei.focus();return}ei.isFocused&&ei.isOpen?ei.blur():ei.focus()}onMouseDown(){}onChange(){ll(this.input,"input"),ll(this.input,"change")}onPaste(ei){var ti=this;if(ti.isInputHidden||ti.isLocked){fn(ei);return}ti.settings.splitOn&&setTimeout(()=>{var ni=ti.inputValue();if(ni.match(ti.settings.splitOn)){var ri=ni.trim().split(ti.settings.splitOn);En(ri,oi=>{Xn(oi)&&(this.options[oi]?ti.addItem(oi):ti.createItem(oi))})}},0)}onKeyPress(ei){var ti=this;if(ti.isLocked){fn(ei);return}var ni=String.fromCharCode(ei.keyCode||ei.which);if(ti.settings.create&&ti.settings.mode==="multi"&&ni===ti.settings.delimiter){ti.createItem(),fn(ei);return}}onKeyDown(ei){var ti=this;if(ti.ignoreHover=!0,ti.isLocked){ei.keyCode!==9&&fn(ei);return}switch(ei.keyCode){case 65:if(Io(fa,ei)&&ti.control_input.value==""){fn(ei),ti.selectAll();return}break;case 27:ti.isOpen&&(fn(ei,!0),ti.close()),ti.clearActiveItems();return;case 40:if(!ti.isOpen&&ti.hasOptions)ti.open();else if(ti.activeOption){let ni=ti.getAdjacent(ti.activeOption,1);ni&&ti.setActiveOption(ni)}fn(ei);return;case 38:if(ti.activeOption){let ni=ti.getAdjacent(ti.activeOption,-1);ni&&ti.setActiveOption(ni)}fn(ei);return;case 13:ti.canSelect(ti.activeOption)?(ti.onOptionSelect(ei,ti.activeOption),fn(ei)):ti.settings.create&&ti.createItem()?fn(ei):document.activeElement==ti.control_input&&ti.isOpen&&fn(ei);return;case 37:ti.advanceSelection(-1,ei);return;case 39:ti.advanceSelection(1,ei);return;case 9:ti.settings.selectOnTab&&(ti.canSelect(ti.activeOption)&&(ti.onOptionSelect(ei,ti.activeOption),fn(ei)),ti.settings.create&&ti.createItem()&&fn(ei));return;case 8:case 46:ti.deleteSelection(ei);return}ti.isInputHidden&&!Io(fa,ei)&&fn(ei)}onInput(ei){if(this.isLocked)return;let ti=this.inputValue();if(this.lastValue!==ti){if(this.lastValue=ti,ti==""){this._onInput();return}this.refreshTimeout&&window.clearTimeout(this.refreshTimeout),this.refreshTimeout=$d(()=>{this.refreshTimeout=null,this._onInput()},this.settings.refreshThrottle)}}_onInput(){let ei=this.lastValue;this.settings.shouldLoad.call(this,ei)&&this.load(ei),this.refreshOptions(),this.trigger("type",ei)}onOptionHover(ei,ti){this.ignoreHover||this.setActiveOption(ti,!1)}onFocus(ei){var ti=this,ni=ti.isFocused;if(ti.isDisabled||ti.isReadOnly){ti.blur(),fn(ei);return}ti.ignoreFocus||(ti.isFocused=!0,ti.settings.preload==="focus"&&ti.preload(),ni||ti.trigger("focus"),ti.activeItems.length||(ti.inputState(),ti.refreshOptions(!!ti.settings.openOnFocus)),ti.refreshState())}onBlur(ei){if(document.hasFocus()!==!1){var ti=this;if(ti.isFocused){ti.isFocused=!1,ti.ignoreFocus=!1;var ni=()=>{ti.close(),ti.setActiveItem(),ti.setCaret(ti.items.length),ti.trigger("blur")};ti.settings.create&&ti.settings.createOnBlur?ti.createItem(null,ni):ni()}}}onOptionSelect(ei,ti){var ni,ri=this;ti.parentElement&&ti.parentElement.matches("[data-disabled]")||(ti.classList.contains("create")?ri.createItem(null,()=>{ri.settings.closeAfterSelect&&ri.close()}):(ni=ti.dataset.value,typeof ni!="undefined"&&(ri.lastQuery=null,ri.addItem(ni),ri.settings.closeAfterSelect&&ri.close(),!ri.settings.hideSelected&&ei.type&&/click/.test(ei.type)&&ri.setActiveOption(ti))))}canSelect(ei){return!!(this.isOpen&&ei&&this.dropdown_content.contains(ei))}onItemSelect(ei,ti){var ni=this;return!ni.isLocked&&ni.settings.mode==="multi"?(fn(ei),ni.setActiveItem(ti,ei),!0):!1}canLoad(ei){return!(!this.settings.load||this.loadedSearches.hasOwnProperty(ei))}load(ei){let ti=this;if(!ti.canLoad(ei))return;jn(ti.wrapper,ti.settings.loadingClass),ti.loading++;let ni=ti.loadCallback.bind(ti);ti.settings.load.call(ti,ei,ni)}loadCallback(ei,ti){let ni=this;ni.loading=Math.max(ni.loading-1,0),ni.lastQuery=null,ni.clearActiveOption(),ni.setupOptions(ei,ti),ni.refreshOptions(ni.isFocused&&!ni.isInputHidden),ni.loading||bo(ni.wrapper,ni.settings.loadingClass),ni.trigger("load",ei,ti)}preload(){var ei=this.wrapper.classList;ei.contains("preloaded")||(ei.add("preloaded"),this.load(""))}setTextboxValue(ei=""){var ti=this.control_input,ni=ti.value!==ei;ni&&(ti.value=ei,ll(ti,"update"),this.lastValue=ei)}getValue(){return this.is_select_tag&&this.input.hasAttribute("multiple")?this.items:this.items.join(this.settings.delimiter)}setValue(ei,ti){var ni=ti?[]:["change"];Oc(this,ni,()=>{this.clear(ti),this.addItems(ei,ti)})}setMaxItems(ei){ei===0&&(ei=null),this.settings.maxItems=ei,this.refreshState()}setActiveItem(ei,ti){var ni=this,ri,oi,si,ai,li,ui;if(ni.settings.mode!=="single"){if(!ei){ni.clearActiveItems(),ni.isFocused&&ni.inputState();return}if(ri=ti&&ti.type.toLowerCase(),ri==="click"&&Io("shiftKey",ti)&&ni.activeItems.length){for(ui=ni.getLastActive(),si=Array.prototype.indexOf.call(ni.control.children,ui),ai=Array.prototype.indexOf.call(ni.control.children,ei),si>ai&&(li=si,si=ai,ai=li),oi=si;oi<=ai;oi++)ei=ni.control.children[oi],ni.activeItems.indexOf(ei)===-1&&ni.setActiveItemClass(ei);fn(ti)}else ri==="click"&&Io(fa,ti)||ri==="keydown"&&Io("shiftKey",ti)?ei.classList.contains("active")?ni.removeActiveItem(ei):ni.setActiveItemClass(ei):(ni.clearActiveItems(),ni.setActiveItemClass(ei));ni.inputState(),ni.isFocused||ni.focus()}}setActiveItemClass(ei){let ti=this,ni=ti.control.querySelector(".last-active");ni&&bo(ni,"last-active"),jn(ei,"active last-active"),ti.trigger("item_select",ei),ti.activeItems.indexOf(ei)==-1&&ti.activeItems.push(ei)}removeActiveItem(ei){var ti=this.activeItems.indexOf(ei);this.activeItems.splice(ti,1),bo(ei,"active")}clearActiveItems(){bo(this.activeItems,"active"),this.activeItems=[]}setActiveOption(ei,ti=!0){ei!==this.activeOption&&(this.clearActiveOption(),ei&&(this.activeOption=ei,an(this.focus_node,{"aria-activedescendant":ei.getAttribute("id")}),an(ei,{"aria-selected":"true"}),jn(ei,"active"),ti&&this.scrollToOption(ei)))}scrollToOption(ei,ti){if(!ei)return;let ni=this.dropdown_content,ri=ni.clientHeight,oi=ni.scrollTop||0,si=ei.offsetHeight,ai=ei.getBoundingClientRect().top-ni.getBoundingClientRect().top+oi;ai+si>ri+oi?this.scroll(ai-ri+si,ti):ai{ei.setActiveItemClass(ni)}))}inputState(){var ei=this;ei.control.contains(ei.control_input)&&(an(ei.control_input,{placeholder:ei.settings.placeholder}),ei.activeItems.length>0||!ei.isFocused&&ei.settings.hidePlaceholder&&ei.items.length>0?(ei.setTextboxValue(),ei.isInputHidden=!0):(ei.settings.hidePlaceholder&&ei.items.length>0&&an(ei.control_input,{placeholder:""}),ei.isInputHidden=!1),ei.wrapper.classList.toggle("input-hidden",ei.isInputHidden))}inputValue(){return this.control_input.value.trim()}focus(){var ei=this;ei.isDisabled||ei.isReadOnly||(ei.ignoreFocus=!0,ei.control_input.offsetWidth?ei.control_input.focus():ei.focus_node.focus(),setTimeout(()=>{ei.ignoreFocus=!1,ei.onFocus()},0))}blur(){this.focus_node.blur(),this.onBlur()}getScoreFunction(ei){return this.sifter.getScoreFunction(ei,this.getSearchOptions())}getSearchOptions(){var ei=this.settings,ti=ei.sortField;return typeof ei.sortField=="string"&&(ti=[{field:ei.sortField}]),{fields:ei.searchField,conjunction:ei.searchConjunction,sort:ti,nesting:ei.nesting}}search(ei){var ti,ni,ri=this,oi=this.getSearchOptions();if(ri.settings.score&&(ni=ri.settings.score.call(ri,ei),typeof ni!="function"))throw new Error('Tom Select "score" setting must be a function that returns a function');return ei!==ri.lastQuery?(ri.lastQuery=ei,ti=ri.sifter.search(ei,Object.assign(oi,{score:ni})),ri.currentResults=ti):ti=Object.assign({},ri.currentResults),ri.settings.hideSelected&&(ti.items=ti.items.filter(si=>{let ai=Xn(si.id);return!(ai&&ri.items.indexOf(ai)!==-1)})),ti}refreshOptions(ei=!0){var ti,ni,ri,oi,si,ai,li,ui,ci,di;let pi={},yi=[];var gi=this,vi=gi.inputValue();let Ei=vi===gi.lastQuery||vi==""&&gi.lastQuery==null;var Si=gi.search(vi),xi=null,Li=gi.settings.shouldOpen||!1,Oi=gi.dropdown_content;Ei&&(xi=gi.activeOption,xi&&(ci=xi.closest("[data-group]"))),oi=Si.items.length,typeof gi.settings.maxOptions=="number"&&(oi=Math.min(oi,gi.settings.maxOptions)),oi>0&&(Li=!0);let zi=(ki,Mi)=>{let Ai=pi[ki];if(Ai!==void 0){let Ci=yi[Ai];if(Ci!==void 0)return[Ai,Ci.fragment]}let qi=document.createDocumentFragment();return Ai=yi.length,yi.push({fragment:qi,order:Mi,optgroup:ki}),[Ai,qi]};for(ti=0;ti0&&(Ci=Ci.cloneNode(!0),an(Ci,{id:Ai.$id+"-clone-"+ni,"aria-selected":null}),Ci.classList.add("ts-cloned"),bo(Ci,"active"),gi.activeOption&&gi.activeOption.dataset.value==Mi&&ci&&ci.dataset.group===si.toString()&&(xi=Ci)),rn.appendChild(Ci),si!=""&&(pi[si]=gn)}}gi.settings.lockOptgroupOrder&&yi.sort((ki,Mi)=>ki.order-Mi.order),li=document.createDocumentFragment(),En(yi,ki=>{let Mi=ki.fragment,Ai=ki.optgroup;if(!Mi||!Mi.children.length)return;let qi=gi.optgroups[Ai];if(qi!==void 0){let Ci=document.createDocumentFragment(),Qi=gi.render("optgroup_header",qi);Ho(Ci,Qi),Ho(Ci,Mi);let Ji=gi.render("optgroup",{group:qi,options:Ci});Ho(li,Ji)}else Ho(li,Mi)}),Oi.innerHTML="",Ho(Oi,li),gi.settings.highlight&&(Yd(Oi),Si.query.length&&Si.tokens.length&&En(Si.tokens,ki=>{Ud(Oi,ki.regex)}));var Vi=ki=>{let Mi=gi.render(ki,{input:vi});return Mi&&(Li=!0,Oi.insertBefore(Mi,Oi.firstChild)),Mi};if(gi.loading?Vi("loading"):gi.settings.shouldLoad.call(gi,vi)?Si.items.length===0&&Vi("no_results"):Vi("not_loading"),ui=gi.canCreate(vi),ui&&(di=Vi("option_create")),gi.hasOptions=Si.items.length>0||ui,Li){if(Si.items.length>0){if(!xi&&gi.settings.mode==="single"&&gi.items[0]!=null&&(xi=gi.getOption(gi.items[0])),!Oi.contains(xi)){let ki=0;di&&!gi.settings.addPrecedence&&(ki=1),xi=gi.selectable()[ki]}}else di&&(xi=di);ei&&!gi.isOpen&&(gi.open(),gi.scrollToOption(xi,"auto")),gi.setActiveOption(xi)}else gi.clearActiveOption(),ei&&gi.isOpen&&gi.close(!1)}selectable(){return this.dropdown_content.querySelectorAll("[data-selectable]")}addOption(ei,ti=!1){let ni=this;if(Array.isArray(ei))return ni.addOptions(ei,ti),!1;let ri=Xn(ei[ni.settings.valueField]);return ri===null||ni.options.hasOwnProperty(ri)?!1:(ei.$order=ei.$order||++ni.order,ei.$id=ni.inputId+"-opt-"+ei.$order,ni.options[ri]=ei,ni.lastQuery=null,ti&&(ni.userOptions[ri]=ti,ni.trigger("option_add",ri,ei)),ri)}addOptions(ei,ti=!1){En(ei,ni=>{this.addOption(ni,ti)})}registerOption(ei){return this.addOption(ei)}registerOptionGroup(ei){var ti=Xn(ei[this.settings.optgroupValueField]);return ti===null?!1:(ei.$order=ei.$order||++this.order,this.optgroups[ti]=ei,ti)}addOptionGroup(ei,ti){var ni;ti[this.settings.optgroupValueField]=ei,(ni=this.registerOptionGroup(ti))&&this.trigger("optgroup_add",ni,ti)}removeOptionGroup(ei){this.optgroups.hasOwnProperty(ei)&&(delete this.optgroups[ei],this.clearCache(),this.trigger("optgroup_remove",ei))}clearOptionGroups(){this.optgroups={},this.clearCache(),this.trigger("optgroup_clear")}updateOption(ei,ti){let ni=this;var ri,oi;let si=Xn(ei),ai=Xn(ti[ni.settings.valueField]);if(si===null)return;let li=ni.options[si];if(li==null)return;if(typeof ai!="string")throw new Error("Value must be set in option data");let ui=ni.getOption(si),ci=ni.getItem(si);if(ti.$order=ti.$order||li.$order,delete ni.options[si],ni.uncacheValue(ai),ni.options[ai]=ti,ui){if(ni.dropdown_content.contains(ui)){let di=ni._render("option",ti);da(ui,di),ni.activeOption===ui&&ni.setActiveOption(di)}ui.remove()}ci&&(oi=ni.items.indexOf(si),oi!==-1&&ni.items.splice(oi,1,ai),ri=ni._render("item",ti),ci.classList.contains("active")&&jn(ri,"active"),da(ci,ri)),ni.lastQuery=null}removeOption(ei,ti){let ni=this;ei=ca(ei),ni.uncacheValue(ei),delete ni.userOptions[ei],delete ni.options[ei],ni.lastQuery=null,ni.trigger("option_remove",ei),ni.removeItem(ei,ti)}clearOptions(ei){let ti=(ei||this.clearFilter).bind(this);this.loadedSearches={},this.userOptions={},this.clearCache();let ni={};En(this.options,(ri,oi)=>{ti(ri,oi)&&(ni[oi]=ri)}),this.options=this.sifter.items=ni,this.lastQuery=null,this.trigger("option_clear")}clearFilter(ei,ti){return this.items.indexOf(ti)>=0}getOption(ei,ti=!1){let ni=Xn(ei);if(ni===null)return null;let ri=this.options[ni];if(ri!=null){if(ri.$div)return ri.$div;if(ti)return this._render("option",ri)}return null}getAdjacent(ei,ti,ni="option"){var ri=this,oi;if(!ei)return null;ni=="item"?oi=ri.controlChildren():oi=ri.dropdown_content.querySelectorAll("[data-selectable]");for(let si=0;si0?oi[si+1]:oi[si-1];return null}getItem(ei){if(typeof ei=="object")return ei;var ti=Xn(ei);return ti!==null?this.control.querySelector(`[data-value="${Lc(ti)}"]`):null}addItems(ei,ti){var ni=this,ri=Array.isArray(ei)?ei:[ei];ri=ri.filter(si=>ni.items.indexOf(si)===-1);let oi=ri[ri.length-1];ri.forEach(si=>{ni.isPending=si!==oi,ni.addItem(si,ti)})}addItem(ei,ti){var ni=ti?[]:["change","dropdown_close"];Oc(this,ni,()=>{var ri,oi;let si=this,ai=si.settings.mode,li=Xn(ei);if(!(li&&si.items.indexOf(li)!==-1&&(ai==="single"&&si.close(),ai==="single"||!si.settings.duplicates))&&!(li===null||!si.options.hasOwnProperty(li))&&(ai==="single"&&si.clear(ti),!(ai==="multi"&&si.isFull()))){if(ri=si._render("item",si.options[li]),si.control.contains(ri)&&(ri=ri.cloneNode(!0)),oi=si.isFull(),si.items.splice(si.caretPos,0,li),si.insertAtCaret(ri),si.isSetup){if(!si.isPending&&si.settings.hideSelected){let ui=si.getOption(li),ci=si.getAdjacent(ui,1);ci&&si.setActiveOption(ci)}!si.isPending&&!si.settings.closeAfterSelect&&si.refreshOptions(si.isFocused&&ai!=="single"),si.settings.closeAfterSelect!=!1&&si.isFull()?si.close():si.isPending||si.positionDropdown(),si.trigger("item_add",li,ri),si.isPending||si.updateOriginalInput({silent:ti})}(!si.isPending||!oi&&si.isFull())&&(si.inputState(),si.refreshState())}})}removeItem(ei=null,ti){let ni=this;if(ei=ni.getItem(ei),!ei)return;var ri,oi;let si=ei.dataset.value;ri=Nc(ei),ei.remove(),ei.classList.contains("active")&&(oi=ni.activeItems.indexOf(ei),ni.activeItems.splice(oi,1),bo(ei,"active")),ni.items.splice(ri,1),ni.lastQuery=null,!ni.settings.persist&&ni.userOptions.hasOwnProperty(si)&&ni.removeOption(si,ti),ri{}){arguments.length===3&&(ti=arguments[2]),typeof ti!="function"&&(ti=()=>{});var ni=this,ri=ni.caretPos,oi;if(ei=ei||ni.inputValue(),!ni.canCreate(ei))return ti(),!1;ni.lock();var si=!1,ai=li=>{if(ni.unlock(),!li||typeof li!="object")return ti();var ui=Xn(li[ni.settings.valueField]);if(typeof ui!="string")return ti();ni.setTextboxValue(),ni.addOption(li,!0),ni.setCaret(ri),ni.addItem(ui),ti(li),si=!0};return typeof ni.settings.create=="function"?oi=ni.settings.create.call(this,ei,ai):oi={[ni.settings.labelField]:ei,[ni.settings.valueField]:ei},si||ai(oi),!0}refreshItems(){var ei=this;ei.lastQuery=null,ei.isSetup&&ei.addItems(ei.items),ei.updateOriginalInput(),ei.refreshState()}refreshState(){let ei=this;ei.refreshValidityState();let ti=ei.isFull(),ni=ei.isLocked;ei.wrapper.classList.toggle("rtl",ei.rtl);let ri=ei.wrapper.classList;ri.toggle("focus",ei.isFocused),ri.toggle("disabled",ei.isDisabled),ri.toggle("readonly",ei.isReadOnly),ri.toggle("required",ei.isRequired),ri.toggle("invalid",!ei.isValid),ri.toggle("locked",ni),ri.toggle("full",ti),ri.toggle("input-active",ei.isFocused&&!ei.isInputHidden),ri.toggle("dropdown-active",ei.isOpen),ri.toggle("has-options",Wd(ei.options)),ri.toggle("has-items",ei.items.length>0)}refreshValidityState(){var ei=this;ei.input.validity&&(ei.isValid=ei.input.validity.valid,ei.isInvalid=!ei.isValid)}isFull(){return this.settings.maxItems!==null&&this.items.length>=this.settings.maxItems}updateOriginalInput(ei={}){let ti=this;var ni,ri;let oi=ti.input.querySelector('option[value=""]');if(ti.is_select_tag){let li=function(ui,ci,di){return ui||(ui=no('")),ui!=oi&&ti.input.append(ui),si.push(ui),(ui!=oi||ai>0)&&(ui.selected=!0),ui},si=[],ai=ti.input.querySelectorAll("option:checked").length;ti.input.querySelectorAll("option:checked").forEach(ui=>{ui.selected=!1}),ti.items.length==0&&ti.settings.mode=="single"?li(oi,"",""):ti.items.forEach(ui=>{if(ni=ti.options[ui],ri=ni[ti.settings.labelField]||"",si.includes(ni.$option)){let ci=ti.input.querySelector(`option[value="${Lc(ui)}"]:not(:checked)`);li(ci,ui,ri)}else ni.$option=li(ni.$option,ui,ri)})}else ti.input.value=ti.getValue();ti.isSetup&&(ei.silent||ti.trigger("change",ti.getValue()))}open(){var ei=this;ei.isLocked||ei.isOpen||ei.settings.mode==="multi"&&ei.isFull()||(ei.isOpen=!0,an(ei.focus_node,{"aria-expanded":"true"}),ei.refreshState(),ua(ei.dropdown,{visibility:"hidden",display:"block"}),ei.positionDropdown(),ua(ei.dropdown,{visibility:"visible",display:"block"}),ei.focus(),ei.trigger("dropdown_open",ei.dropdown))}close(ei=!0){var ti=this,ni=ti.isOpen;ei&&(ti.setTextboxValue(),ti.settings.mode==="single"&&ti.items.length&&ti.inputState()),ti.isOpen=!1,an(ti.focus_node,{"aria-expanded":"false"}),ua(ti.dropdown,{display:"none"}),ti.settings.hideSelected&&ti.clearActiveOption(),ti.refreshState(),ni&&ti.trigger("dropdown_close",ti.dropdown)}positionDropdown(){if(this.settings.dropdownParent==="body"){var ei=this.control,ti=ei.getBoundingClientRect(),ni=ei.offsetHeight+ti.top+window.scrollY,ri=ti.left+window.scrollX;ua(this.dropdown,{width:ti.width+"px",top:ni+"px",left:ri+"px"})}}clear(ei){var ti=this;if(ti.items.length){var ni=ti.controlChildren();En(ni,ri=>{ti.removeItem(ri,!0)}),ti.inputState(),ei||ti.updateOriginalInput(),ti.trigger("clear")}}insertAtCaret(ei){let ti=this,ni=ti.caretPos,ri=ti.control;ri.insertBefore(ei,ri.children[ni]||null),ti.setCaret(ni+1)}deleteSelection(ei){var ti,ni,ri,oi,si=this;ti=ei&&ei.keyCode===8?-1:1,ni=zd(si.control_input);let ai=[];if(si.activeItems.length)oi=kc(si.activeItems,ti),ri=Nc(oi),ti>0&&ri++,En(si.activeItems,li=>ai.push(li));else if((si.isFocused||si.settings.mode==="single")&&si.items.length){let li=si.controlChildren(),ui;ti<0&&ni.start===0&&ni.length===0?ui=li[si.caretPos-1]:ti>0&&ni.start===si.inputValue().length&&(ui=li[si.caretPos]),ui!==void 0&&ai.push(ui)}if(!si.shouldDelete(ai,ei))return!1;for(fn(ei,!0),typeof ri!="undefined"&&si.setCaret(ri);ai.length;)si.removeItem(ai.pop());return si.inputState(),si.positionDropdown(),si.refreshOptions(!1),!0}shouldDelete(ei,ti){let ni=ei.map(ri=>ri.dataset.value);return!(!ni.length||typeof this.settings.onDelete=="function"&&this.settings.onDelete(ni,ti)===!1)}advanceSelection(ei,ti){var ni,ri,oi=this;oi.rtl&&(ei*=-1),!oi.inputValue().length&&(Io(fa,ti)||Io("shiftKey",ti)?(ni=oi.getLastActive(ei),ni?ni.classList.contains("active")?ri=oi.getAdjacent(ni,ei,"item"):ri=ni:ei>0?ri=oi.control_input.nextElementSibling:ri=oi.control_input.previousElementSibling,ri&&(ri.classList.contains("active")&&oi.removeActiveItem(ni),oi.setActiveItemClass(ri))):oi.moveCaret(ei))}moveCaret(ei){}getLastActive(ei){let ti=this.control.querySelector(".last-active");if(ti)return ti;var ni=this.control.querySelectorAll(".active");if(ni)return kc(ni,ei)}setCaret(ei){this.caretPos=this.items.length}controlChildren(){return Array.from(this.control.querySelectorAll("[data-ts-item]"))}lock(){this.setLocked(!0)}unlock(){this.setLocked(!1)}setLocked(ei=this.isReadOnly||this.isDisabled){this.isLocked=ei,this.refreshState()}disable(){this.setDisabled(!0),this.close()}enable(){this.setDisabled(!1)}setDisabled(ei){this.focus_node.tabIndex=ei?-1:this.tabIndex,this.isDisabled=ei,this.input.disabled=ei,this.control_input.disabled=ei,this.setLocked()}setReadOnly(ei){this.isReadOnly=ei,this.input.readOnly=ei,this.control_input.readOnly=ei,this.setLocked()}destroy(){var ei=this,ti=ei.revertSettings;ei.trigger("destroy"),ei.off(),ei.wrapper.remove(),ei.dropdown.remove(),ei.input.innerHTML=ti.innerHTML,ei.input.tabIndex=ti.tabIndex,bo(ei.input,"tomselected","ts-hidden-accessible"),ei._destroy(),delete ei.input.tomselect}render(ei,ti){var ni,ri;let oi=this;if(typeof this.settings.render[ei]!="function"||(ri=oi.settings.render[ei].call(this,ti,sl),!ri))return null;if(ri=no(ri),ei==="option"||ei==="option_create"?ti[oi.settings.disabledField]?an(ri,{"aria-disabled":"true"}):an(ri,{"data-selectable":""}):ei==="optgroup"&&(ni=ti.group[oi.settings.optgroupValueField],an(ri,{"data-group":ni}),ti.group[oi.settings.disabledField]&&an(ri,{"data-disabled":""})),ei==="option"||ei==="item"){let si=ca(ti[oi.settings.valueField]);an(ri,{"data-value":si}),ei==="item"?(jn(ri,oi.settings.itemClass),an(ri,{"data-ts-item":""})):(jn(ri,oi.settings.optionClass),an(ri,{role:"option",id:ti.$id}),ti.$div=ri,oi.options[si]=ti)}return ri}_render(ei,ti){let ni=this.render(ei,ti);if(ni==null)throw"HTMLElement expected";return ni}clearCache(){En(this.options,ei=>{ei.$div&&(ei.$div.remove(),delete ei.$div)})}uncacheValue(ei){let ti=this.getOption(ei);ti&&ti.remove()}canCreate(ei){return this.settings.create&&ei.length>0&&this.settings.createFilter.call(this,ei)}hook(ei,ti,ni){var ri=this,oi=ri[ti];ri[ti]=function(){var si,ai;return ei==="after"&&(si=oi.apply(ri,arguments)),ai=ni.apply(ri,arguments),ei==="instead"?ai:(ei==="before"&&(si=oi.apply(ri,arguments)),si)}}};var pb=(ii,ei,ti,ni)=>{ii.addEventListener(ei,ti,ni)};function Xd(){pb(this.input,"change",()=>{this.sync()})}var mb=ii=>typeof ii=="undefined"||ii===null?null:gb(ii),gb=ii=>typeof ii=="boolean"?ii?"1":"0":ii+"",Jd=(ii,ei=!1)=>{ii&&(ii.preventDefault(),ei&&ii.stopPropagation())},vb=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(yb(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},yb=ii=>typeof ii=="string"&&ii.indexOf("<")>-1;function Zd(ii){var ei=this,ti=ei.onOptionSelect;ei.settings.hideSelected=!1;let ni=Object.assign({className:"tomselect-checkbox",checkedClassNames:void 0,uncheckedClassNames:void 0},ii);var ri=function(ai,li){li?(ai.checked=!0,ni.uncheckedClassNames&&ai.classList.remove(...ni.uncheckedClassNames),ni.checkedClassNames&&ai.classList.add(...ni.checkedClassNames)):(ai.checked=!1,ni.checkedClassNames&&ai.classList.remove(...ni.checkedClassNames),ni.uncheckedClassNames&&ai.classList.add(...ni.uncheckedClassNames))},oi=function(ai){setTimeout(()=>{var li=ai.querySelector("input."+ni.className);li instanceof HTMLInputElement&&ri(li,ai.classList.contains("selected"))},1)};ei.hook("after","setupTemplates",()=>{var si=ei.settings.render.option;ei.settings.render.option=(ai,li)=>{var ui=vb(si.call(ei,ai,li)),ci=document.createElement("input");ni.className&&ci.classList.add(ni.className),ci.addEventListener("click",function(pi){Jd(pi)}),ci.type="checkbox";let di=mb(ai[ei.settings.valueField]);return ri(ci,!!(di&&ei.items.indexOf(di)>-1)),ui.prepend(ci),ui}}),ei.on("item_remove",si=>{var ai=ei.getOption(si);ai&&(ai.classList.remove("selected"),oi(ai))}),ei.on("item_add",si=>{var ai=ei.getOption(si);ai&&oi(ai)}),ei.hook("instead","onOptionSelect",(si,ai)=>{if(ai.classList.contains("selected")){ai.classList.remove("selected"),ei.removeItem(ai.dataset.value),ei.refreshOptions(),Jd(si,!0);return}ti.call(ei,si,ai),oi(ai)})}var bb=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(_b(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},_b=ii=>typeof ii=="string"&&ii.indexOf("<")>-1;function ef(ii){let ei=this,ti=Object.assign({className:"clear-button",title:"Clear All",html:ni=>`
`},ii);ei.on("initialize",()=>{var ni=bb(ti.html(ti));ni.addEventListener("click",ri=>{ei.isLocked||(ei.clear(),ei.settings.mode==="single"&&ei.settings.allowEmptyOption&&ei.addItem(""),ri.preventDefault(),ri.stopPropagation())}),ei.control.appendChild(ni)})}var Eb=(ii,ei=!1)=>{ii&&(ii.preventDefault(),ei&&ii.stopPropagation())},Os=(ii,ei,ti,ni)=>{ii.addEventListener(ei,ti,ni)},wb=(ii,ei)=>{if(Array.isArray(ii))ii.forEach(ei);else for(var ti in ii)ii.hasOwnProperty(ti)&&ei(ii[ti],ti)},xb=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(Tb(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},Tb=ii=>typeof ii=="string"&&ii.indexOf("<")>-1,Cb=(ii,ei)=>{wb(ei,(ti,ni)=>{ti==null?ii.removeAttribute(ni):ii.setAttribute(ni,""+ti)})},Sb=(ii,ei)=>{var ti;(ti=ii.parentNode)==null||ti.insertBefore(ei,ii.nextSibling)},Ab=(ii,ei)=>{var ti;(ti=ii.parentNode)==null||ti.insertBefore(ei,ii)},Db=(ii,ei)=>{do{var ti;if(ei=(ti=ei)==null?void 0:ti.previousElementSibling,ii==ei)return!0}while(ei&&ei.previousElementSibling);return!1};function tf(){var ii=this;if(ii.settings.mode!=="multi")return;var ei=ii.lock,ti=ii.unlock;let ni=!0,ri;ii.hook("after","setupTemplates",()=>{var oi=ii.settings.render.item;ii.settings.render.item=(si,ai)=>{let li=xb(oi.call(ii,si,ai));Cb(li,{draggable:"true"});let ui=vi=>{ni||Eb(vi),vi.stopPropagation()},ci=vi=>{ri=li,setTimeout(()=>{li.classList.add("ts-dragging")},0)},di=vi=>{vi.preventDefault(),li.classList.add("ts-drag-over"),yi(li,ri)},pi=()=>{li.classList.remove("ts-drag-over")},yi=(vi,Ei)=>{Ei!==void 0&&(Db(Ei,li)?Sb(vi,Ei):Ab(vi,Ei))},gi=()=>{var vi;document.querySelectorAll(".ts-drag-over").forEach(Si=>Si.classList.remove("ts-drag-over")),(vi=ri)==null||vi.classList.remove("ts-dragging"),ri=void 0;var Ei=[];ii.control.querySelectorAll("[data-value]").forEach(Si=>{if(Si.dataset.value){let xi=Si.dataset.value;xi&&Ei.push(xi)}}),ii.setValue(Ei)};return Os(li,"mousedown",ui),Os(li,"dragstart",ci),Os(li,"dragenter",di),Os(li,"dragover",di),Os(li,"dragleave",pi),Os(li,"dragend",gi),li}}),ii.hook("instead","lock",()=>(ni=!1,ei.call(ii))),ii.hook("instead","unlock",()=>(ni=!0,ti.call(ii)))}var Ob=(ii,ei=!1)=>{ii&&(ii.preventDefault(),ei&&ii.stopPropagation())},Lb=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(Mb(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},Mb=ii=>typeof ii=="string"&&ii.indexOf("<")>-1;function nf(ii){let ei=this,ti=Object.assign({title:"Untitled",headerClass:"dropdown-header",titleRowClass:"dropdown-header-title",labelClass:"dropdown-header-label",closeClass:"dropdown-header-close",html:ni=>'
'+ni.title+'×
'},ii);ei.on("initialize",()=>{var ni=Lb(ti.html(ti)),ri=ni.querySelector("."+ti.closeClass);ri&&ri.addEventListener("click",oi=>{Ob(oi,!0),ei.close()}),ei.dropdown.insertBefore(ni,ei.dropdown.firstChild)})}var kb=(ii,ei)=>{if(Array.isArray(ii))ii.forEach(ei);else for(var ti in ii)ii.hasOwnProperty(ti)&&ei(ii[ti],ti)},Nb=(ii,...ei)=>{var ti=Rb(ei);ii=Ib(ii),ii.map(ni=>{ti.map(ri=>{ni.classList.remove(ri)})})},Rb=ii=>{var ei=[];return kb(ii,ti=>{typeof ti=="string"&&(ti=ti.trim().split(/[\t\n\f\r\s]/)),Array.isArray(ti)&&(ei=ei.concat(ti))}),ei.filter(Boolean)},Ib=ii=>(Array.isArray(ii)||(ii=[ii]),ii),Hb=(ii,ei)=>{if(!ii)return-1;ei=ei||ii.nodeName;for(var ti=0;ii=ii.previousElementSibling;)ii.matches(ei)&&ti++;return ti};function rf(){var ii=this;ii.hook("instead","setCaret",ei=>{ii.settings.mode==="single"||!ii.control.contains(ii.control_input)?ei=ii.items.length:(ei=Math.max(0,Math.min(ii.items.length,ei)),ei!=ii.caretPos&&!ii.isPending&&ii.controlChildren().forEach((ti,ni)=>{ni{if(!ii.isFocused)return;let ti=ii.getLastActive(ei);if(ti){let ni=Hb(ti);ii.setCaret(ei>0?ni+1:ni),ii.setActiveItem(),Nb(ti,"last-active")}else ii.setCaret(ii.caretPos+ei)})}var Pb=(ii,ei=!1)=>{ii&&(ii.preventDefault(),ei&&ii.stopPropagation())},Fb=(ii,ei,ti,ni)=>{ii.addEventListener(ei,ti,ni)},$b=(ii,ei)=>{if(Array.isArray(ii))ii.forEach(ei);else for(var ti in ii)ii.hasOwnProperty(ti)&&ei(ii[ti],ti)},of=ii=>{if(ii.jquery)return ii[0];if(ii instanceof HTMLElement)return ii;if(Bb(ii)){var ei=document.createElement("template");return ei.innerHTML=ii.trim(),ei.content.firstChild}return document.querySelector(ii)},Bb=ii=>typeof ii=="string"&&ii.indexOf("<")>-1,zb=(ii,...ei)=>{var ti=Vb(ei);ii=jb(ii),ii.map(ni=>{ti.map(ri=>{ni.classList.add(ri)})})},Vb=ii=>{var ei=[];return $b(ii,ti=>{typeof ti=="string"&&(ti=ti.trim().split(/[\t\n\f\r\s]/)),Array.isArray(ti)&&(ei=ei.concat(ti))}),ei.filter(Boolean)},jb=ii=>(Array.isArray(ii)||(ii=[ii]),ii);function sf(){let ii=this;ii.settings.shouldOpen=!0,ii.hook("before","setup",()=>{ii.focus_node=ii.control,zb(ii.control_input,"dropdown-input");let ei=of('