` with the class name `"card"`. This is the element we need to target to change the background color.
+- **Child element:** The card text is wrapped inside a `
` with our `id`. This is the element we need to target to change the font color.
!!! example "Customizing CSS properties in selective components"
=== "my_css_file.css"
- ```css
- /* Apply styling to parent */
- .card:has(#custom-card) {
- background-color: white;
- }
+ ```css
+ /* Apply styling to parent */
+ .card:has(#custom-card) {
+ background-color: white;
+ }
+
+ /* Apply styling to child */
+ #custom-card p {
+ color: black;
+ }
+ ```
- /* Apply styling to child */
- #custom-card p {
- color: black;
- }
- ```
=== "app.py"
```py
import vizro.models as vm
@@ -285,69 +272,65 @@ It's essential to understand the relationship between the targeted CSS class or
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- Lorem ipsum dolor sit amet consectetur adipisicing elit.
- type: card
- id: custom-card
- - text: |
- Lorem ipsum dolor sit amet consectetur adipisicing elit.
- type: card
- title: Changing the card color
+ - components:
+ - text: |
+ Lorem ipsum dolor sit amet consectetur adipisicing elit.
+ type: card
+ id: custom-card
+ - text: |
+ Lorem ipsum dolor sit amet consectetur adipisicing elit.
+ type: card
+ title: Changing the card color
```
- === "Result"
- [![CardCSS]][CardCSS]
-
- [CardCSS]: ../../assets/user_guides/assets/css_change_card.png
+ === "Result"
+ [![CardCSS]][cardcss]
!!! note "Relationship between model ID and CSS ID"
+ Some Vizro components produce a single HTML element with an ID that matches the model ID, allowing you to target it directly using the CSS #id selector. Other components generate multiple HTML elements. Within these, the "core" element will have an ID matching the model ID, while non-core elements may have IDs that are variations of it, such as `{model-id}-title`.
- Some Vizro components produce a single HTML element with an ID that matches the model ID, allowing you to target it
- directly using the CSS #id selector. Other components generate multiple HTML elements. Within these, the "core"
- element will have an ID matching the model ID, while non-core elements may have IDs that are variations of it,
- such as `{model-id}-title`.
+ In all instances, you can determine the correct selector by using Chrome DevTools or a similar tool after setting the appropriate model ID.
- In all instances, you can determine the correct selector by using Chrome DevTools or a similar tool after setting the
- appropriate model ID.
+## Common examples
+### Make your CSS responsive to theme switches with variables
-## Common examples
+To ensure your CSS adapts to theme changes, we recommend using CSS variables (`var`) whenever possible. For a comprehensive list of available variable names, refer to the [Bootstrap documentation](https://getbootstrap.com/docs/5.3/customize/css-variables/). Note that our Bootstrap stylesheet is still under development, so not all Bootstrap variables are currently available. Additionally, you can define your own CSS variables, as demonstrated in the example on [changing the container background color](#change-the-styling-of-a-container).
### Turn off page title
+
See the example above on [hiding the page title on selected pages](#overwrite-css-for-selected-pages).
### Change the background color of a card
+
See the example above on [customizing CSS properties in selective components](#overwrite-css-for-selected-components).
### Change the global font
+
The default fonts for a Vizro app are `Inter, sans-serif, Arial, serif`.
If you need to change the global font, perhaps to adhere to branding guidelines, follow these steps:
1. Download the desired font from a font provider such as [Google Fonts](https://fonts.google.com/).
-2. Place the font file (`.ttf`, `woff2`, etc.) into your `assets` folder. Here’s an example of what the assets folder might look like:
- ![Font Change](../../assets/user_guides/custom_css/font-change.png)
+1. Place the font file (`.ttf`, `woff2`, etc.) into your `assets` folder. Here’s an example of what the assets folder might look like:
-3. Add the font to your CSS file using the `@font-face` rule and apply the font globally to your Vizro app, making sure
-to specify fallback fonts. Add the following to your `custom.css` file:
+ ![Font Change](../../assets/user_guides/custom_css/font-change.png)
+1. Add the font to your CSS file using the `@font-face` rule and apply the font globally to your Vizro app, making sure to specify fallback fonts. Add the following to your `custom.css` file:
```css
@font-face {
- font-family: PlayfairDisplay;
- src: url("PlayfairDisplay-VariableFont_wght.ttf") format("truetype");
+ font-family: PlayfairDisplay;
+ src: url("PlayfairDisplay-VariableFont_wght.ttf") format("truetype");
}
* {
- font-family: PlayfairDisplay, Inter, sans-serif, Arial, serif;
+ font-family: PlayfairDisplay, Inter, sans-serif, Arial, serif;
}
```
-
-4. Note that the modification above applies solely to the dashboard font. To also change the font within the
-Plotly charts, you must specify this at the beginning of your `app.py` file:
+1. Note that the modification above applies solely to the dashboard font. To also change the font within the Plotly charts, you must specify this at the beginning of your `app.py` file:
```python
import plotly.io as pio
@@ -357,34 +340,42 @@ Plotly charts, you must specify this at the beginning of your `app.py` file:
```
### Reposition the logo
-By default, the logo appears in the top left corner of the dashboard. You can move it further to the left or right by
-adjusting the `padding` of the `#page-header` element. Here is an example of how to achieve this:
+
+By default, the logo appears in the top left corner of the dashboard. You can move it further to the left or right by adjusting the `padding` of the `#page-header` element. Here is an example of how to achieve this:
```css
#page-header {
- padding-left: 8px;
+ padding-left: 8px;
}
```
![Logo positioning](../../assets/user_guides/custom_css/logo-position.png)
-
### Change the styling of a container
-If you want to make the subsections of your dashboard stand out more, you can do this by placing your components
-inside a [Container](container.md) and changing the container's styling, for example, background color, borders, padding, etc.
-To do this, you need to change the container's CSS class. Using the DevTool, as explained in the section on
-[identifying the correct CSS selector](#identify-the-correct-css-selector), you'll find that the CSS class for the
-`Container` is `page-component-container`. You can then use this class to set a new `background-color` and `padding`.
+If you want to make the subsections of your dashboard stand out more, you can do this by placing your components inside a [Container](container.md) and changing the container's styling, for example, background color, borders, padding, etc.
+
+To do this, you need to change the container's CSS class. Using the DevTool, as explained in the section on [identifying the correct CSS selector](#identify-the-correct-css-selector), you'll find that the CSS class for the `Container` is `page-component-container`. You can then use this class to set a new `background-color` and `padding`.
!!! example "Style a container"
=== "custom.css"
- ```css
- .page-component-container {
- background: var(--surfaces-bg-card);
- padding: 12px;
- }
- ```
+ ```css
+ /* Assign a variable to the dark and light theme */
+ [data-bs-theme="dark"] {
+ --container-bg-color: #232632;
+ }
+
+ [data-bs-theme="light"] {
+ --container-bg-color: #F5F6F6;
+ }
+
+ /* Use the custom variable var(--container-bg-color) */
+ .page-component-container {
+ background: var(--container-bg-color);
+ padding: 12px;
+ }
+ ```
+
=== "app.py"
```py
import vizro.models as vm
@@ -419,12 +410,12 @@ To do this, you need to change the container's CSS class. Using the DevTool, as
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - title: "Page with subsections"
+ - title: Page with subsections
layout:
grid: [[0, 1]]
components:
- type: container
- title: "Container I"
+ title: Container I
components:
- type: graph
figure:
@@ -434,7 +425,7 @@ To do this, you need to change the container's CSS class. Using the DevTool, as
y: sepal_length
color: species
- type: container
- title: "Container II"
+ title: Container II
components:
- type: graph
figure:
@@ -444,13 +435,11 @@ To do this, you need to change the container's CSS class. Using the DevTool, as
y: sepal_length
color: species
```
- === "Result"
- [![StyleContainer]][StyleContainer]
- [StyleContainer]: ../../assets/user_guides/custom_css/style-container.png
+ === "Result"
+ [![StyleContainer]][stylecontainer]
-You will notice that the background colors of the charts are different. To align it with the colors of the container,
-you can make the charts' background transparent.
+You will notice that the background colors of the charts are different. To align it with the colors of the container, you can make the charts' background transparent.
To make the background of all charts transparent:
@@ -474,3 +463,8 @@ def custom_chart(data_frame):
```
![Transparent charts](../../assets/user_guides/custom_css/transparent-charts.png)
+
+[assetscss]: ../../assets/user_guides/assets/css_change.png
+[cardcss]: ../../assets/user_guides/assets/css_change_card.png
+[pagetitle]: ../../assets/user_guides/assets/css_page_title.png
+[stylecontainer]: ../../assets/user_guides/custom_css/style-container.png
diff --git a/vizro-core/docs/pages/user-guides/custom-figures.md b/vizro-core/docs/pages/user-guides/custom-figures.md
index f135127be..3a178932f 100644
--- a/vizro-core/docs/pages/user-guides/custom-figures.md
+++ b/vizro-core/docs/pages/user-guides/custom-figures.md
@@ -1,41 +1,36 @@
# How to create custom figures
-This guide explains how to create custom figures, which is useful when you need a component that reacts to
-[filter](filters.md) and [parameter](parameters.md) controls.
+This guide explains how to create custom figures, which is useful when you need a component that reacts to [filter](filters.md) and [parameter](parameters.md) controls.
-The [`Figure`][vizro.models.Figure] model accepts the `figure` argument, where you can enter _any_ custom figure function
-as explained in the [user guide on figures](figure.md).
+The [`Figure`][vizro.models.Figure] model accepts the `figure` argument, where you can enter _any_ custom figure function as explained in the [user guide on figures](figure.md).
## When to use a custom figure
-As described in the flowchart detailing [when to use `Figure`](figure.md), custom figures should be used if
-**both** of the following conditions are met:
+
+As described in the flowchart detailing [when to use `Figure`](figure.md), custom figures should be used if **both** of the following conditions are met:
- You need a figure that doesn't fit into the existing pre-defined components ([`Graph`][vizro.models.Graph], [`Table`][vizro.models.Table] or [`AgGrid`][vizro.models.AgGrid]).
- You need a figure that isn't available in our pre-defined figure functions [`vizro.figures`](../API-reference/figure-callables.md).
## Steps to create a custom figure
-1. Define a function that returns a [Dash component](https://dash.plotly.com/#open-source-component-libraries).
-This can, but does not need to, be based on code in our pre-defined figure functions in [`vizro.figures`](../API-reference/figure-callables.md).
-2. Decorate it with `@capture("figure")`.
-3. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
-4. The figure should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments
-will not react to dashboard controls such as [`Filter`](filters.md).
-5. Pass your function to the `figure` argument of the [`Figure`][vizro.models.Figure] model.
+1. Define a function that returns a [Dash component](https://dash.plotly.com/#open-source-component-libraries). This can, but does not need to, be based on code in our pre-defined figure functions in [`vizro.figures`](../API-reference/figure-callables.md).
+1. Decorate it with `@capture("figure")`.
+1. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
+1. The figure should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments will not react to dashboard controls such as [`Filter`](filters.md).
+1. Pass your function to the `figure` argument of the [`Figure`][vizro.models.Figure] model.
The following examples can be used as a base to build more sophisticated figures.
## Examples of custom figures
### Custom KPI card
-To change the design or content of our existing KPI (key performance indicator) cards from
-[`vizro.figures`](../API-reference/figure-callables.md), you can do so by following the steps described above.
-For instance, to make a KPI card with the icon positioned on the right side of the title instead of the left,
-copy and paste the [source code of `kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card) and
-adjust the return statement of the function.
+To change the design or content of our existing KPI (key performance indicator) cards from [`vizro.figures`](../API-reference/figure-callables.md), you can do so by following the steps described above.
+
+For instance, to make a KPI card with the icon positioned on the right side of the title instead of the left, copy and paste the [source code of `kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card) and adjust the return statement of the function.
+
!!! example "Custom KPI card"
=== "app.py"
```{.python pycafe-link}
@@ -107,29 +102,26 @@ adjust the return statement of the function.
```
1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
- 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
- 3. We adjust the return statement to include the icon on the right side of the title. This is achieved by swapping the order of the `html.H2` and `html.P` compared to the original `kpi_card`.
- 4. This creates a [`layout`](layouts.md) with four rows and columns. The KPI cards are positioned in the first two cells, while the remaining cells are empty.
- 5. For more information, refer to the API reference for the [`kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card).
- 6. Our custom figure function `custom_kpi_card` now needs to be passed on to the `vm.Figure`.
+ 1. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 1. We adjust the return statement to include the icon on the right side of the title. This is achieved by swapping the order of the `html.H2` and `html.P` compared to the original `kpi_card`.
+ 1. This creates a [`layout`](layouts.md) with four rows and columns. The KPI cards are positioned in the first two cells, while the remaining cells are empty.
+ 1. For more information, refer to the API reference for the [`kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card).
+ 1. Our custom figure function `custom_kpi_card` now needs to be passed on to the `vm.Figure`.
=== "app.yaml"
- ```yaml
- # Custom figures are currently only possible via Python configuration
- ```
- === "Result"
- [![CustomKPI]][CustomKPI]
+ Custom figures are currently only possible via Python configuration.
- [CustomKPI]: ../../assets/user_guides/figure/custom_kpi.png
+ === "Result"
+ [![CustomKPI]][customkpi]
### Dynamic HTML header
-You can create a custom figure for any [Dash component](https://dash.plotly.com/#open-source-component-libraries).
-Below is an example of a custom figure that returns a `html.H2` component that dynamically updates based on the selected
-name from a filter.
+
+You can create a custom figure for any [Dash component](https://dash.plotly.com/#open-source-component-libraries). Below is an example of a custom figure that returns a `html.H2` component that dynamically updates based on the selected name from a filter.
+
!!! example "Dynamic HTML header"
=== "app.py"
```{.python pycafe-link}
@@ -159,27 +151,24 @@ name from a filter.
```
1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
- 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
- 3. We return a `html.H2` component that dynamically updates based on the selected name from the filter.
- 4. Our custom figure function `dynamic_html_header` now needs to be passed on to the `vm.Figure`.
+ 1. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 1. We return a `html.H2` component that dynamically updates based on the selected name from the filter.
+ 1. Our custom figure function `dynamic_html_header` now needs to be passed on to the `vm.Figure`.
=== "app.yaml"
- ```yaml
- # Custom figures are currently only possible via Python configuration
- ```
- === "Result"
- [![CustomHTML]][CustomHTML]
+ Custom figures are currently only possible via Python configuration.
- [CustomHTML]: ../../assets/user_guides/figure/custom_html.png
+ === "Result"
+ [![CustomHTML]][customhtml]
-
### Dynamic number of cards
-The example below shows how to create multiple cards created from a `pandas.DataFrame` where the
-number of cards displayed dynamically adjusts based on a `vm.Parameter`.
+
+The example below shows how to create multiple cards created from a `pandas.DataFrame` where the number of cards displayed dynamically adjusts based on a `vm.Parameter`.
+
!!! example "Dynamic number of cards"
=== "app.py"
```py
@@ -239,40 +228,39 @@ number of cards displayed dynamically adjusts based on a `vm.Parameter`.
```
1. Here we decorate our custom figure function with the `@capture("figure")` decorator.
- 2. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
- 3. Our decorated figure function `multiple_cards` now needs to be passed on to the `vm.Figure`.
- 4. We add a [`vm.Parameter`](parameters.md) to dynamically adjust the number of cards displayed.
- The parameter targets the `n_rows` argument of the `multiple_cards` function, determining the number of rows
- taken from the data.
+ 1. The custom figure function needs to have a `data_frame` argument and return a `Dash` component.
+ 1. Our decorated figure function `multiple_cards` now needs to be passed on to the `vm.Figure`.
+ 1. We add a [`vm.Parameter`](parameters.md) to dynamically adjust the number of cards displayed. The parameter targets the `n_rows` argument of the `multiple_cards` function, determining the number of rows taken from the data.
Run and edit this code in PyCafe
=== "styling.css"
```css
.multiple-cards-container {
- display: flex;
- flex-wrap: wrap;
- gap: 12px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
}
.figure-container {
- height: unset;
- width: unset;
+ height: unset;
+ width: unset;
}
.figure-container .card {
- height: 210px;
- width: 240px;
+ height: 210px;
+ width: 240px;
}
```
- === "app.yaml"
- ```yaml
- # Custom figures are currently only possible via Python configuration
- ```
- === "Result"
- [![CustomFigure]][CustomFigure]
- [CustomFigure]: ../../assets/user_guides/figure/custom_multiple_cards.png
+ === "app.yaml"
+ Custom figures are currently only possible via Python configuration.
+ === "Result"
+ [![CustomFigure]][customfigure]
+
+[customfigure]: ../../assets/user_guides/figure/custom_multiple_cards.png
+[customhtml]: ../../assets/user_guides/figure/custom_html.png
+[customkpi]: ../../assets/user_guides/figure/custom_kpi.png
diff --git a/vizro-core/docs/pages/user-guides/custom-tables.md b/vizro-core/docs/pages/user-guides/custom-tables.md
index 8fa5f5252..42748820b 100644
--- a/vizro-core/docs/pages/user-guides/custom-tables.md
+++ b/vizro-core/docs/pages/user-guides/custom-tables.md
@@ -1,21 +1,18 @@
# How to create custom Dash AG Grids and Dash DataTables
-In cases where the available arguments for the [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] models are not sufficient,
-you can create a custom Dash AG Grid or Dash DataTable.
+In cases where the available arguments for the [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] models are not sufficient, you can create a custom Dash AG Grid or Dash DataTable.
-The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] model accept the `figure` argument, where you can enter
-_any_ [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] chart as explained in the [user guide on tables](table.md).
+The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] model accept the `figure` argument, where you can enter _any_ [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] chart as explained in the [user guide on tables](table.md).
One reason could be that you want to create a table/grid that requires computations that can be controlled by parameters (see the example below).
### Steps to create a custom table
1. Define a function that returns a `dash_ag_grid.AgGrid` or `dash_table.DataTable` object.
-2. Decorate it with `@capture("ag_grid")` or `@capture("table")`.
-3. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
-4. The table should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments
-will not react to dashboard controls such as [`Filter`](filters.md).
-5. Pass your function to the `figure` argument of the [`Table`][vizro.models.Table] or [`AgGrid`][vizro.models.AgGrid] model.
+1. Decorate it with `@capture("ag_grid")` or `@capture("table")`.
+1. The function must accept a `data_frame` argument (of type `pandas.DataFrame`).
+1. The table should be derived from and require only one `pandas.DataFrame`. Dataframes from other arguments will not react to dashboard controls such as [`Filter`](filters.md).
+1. Pass your function to the `figure` argument of the [`Table`][vizro.models.Table] or [`AgGrid`][vizro.models.AgGrid] model.
The following examples show a possible version of a custom table. In this case the argument `chosen_columns` was added, which you can control with a parameter:
@@ -38,10 +35,10 @@ The following examples show a possible version of a custom table. In this case t
columns = [{"name": i, "id": i} for i in chosen_columns]
defaults = {
"style_as_list_view": True,
- "style_data": {"border_bottom": "1px solid var(--border-subtle-alpha-01)", "height": "40px"},
+ "style_data": {"border_bottom": "1px solid var(--border-subtleAlpha01)", "height": "40px"},
"style_header": {
- "border_bottom": "1px solid var(--state-overlays-selected-hover)",
- "border_top": "1px solid var(--main-container-bg-color)",
+ "border_bottom": "1px solid var(--stateOverlays-selectedHover)",
+ "border_top": "1px solid var(--right-side-bg)",
"height": "32px",
},
}
@@ -70,14 +67,12 @@ The following examples show a possible version of a custom table. In this case t
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
- ```yaml
- # Custom tables are currently only possible via Python configuration
- ```
- === "Result"
- [![Table3]][Table3]
+ Custom tables are currently only possible via Python configuration.
- [Table3]: ../../assets/user_guides/table/custom_table.png
+ === "Result"
+ [![Table3]][table3]
??? example "Custom Dash AgGrid"
=== "app.py"
@@ -136,11 +131,12 @@ The following examples show a possible version of a custom table. In this case t
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
- ```yaml
- # Custom Ag Grids are currently only possible via Python configuration
- ```
+ Custom Ag Grids are currently only possible via Python configuration.
+
=== "Result"
- [![GridCustom]][GridCustom]
+ [![GridCustom]][gridcustom]
- [GridCustom]: ../../assets/user_guides/table/custom_grid.png
+[gridcustom]: ../../assets/user_guides/table/custom_grid.png
+[table3]: ../../assets/user_guides/table/custom_table.png
diff --git a/vizro-core/docs/pages/user-guides/dashboard.md b/vizro-core/docs/pages/user-guides/dashboard.md
index 0b37e03fa..244f65256 100644
--- a/vizro-core/docs/pages/user-guides/dashboard.md
+++ b/vizro-core/docs/pages/user-guides/dashboard.md
@@ -1,16 +1,15 @@
# How to create a dashboard
-This guide shows you how to configure and call a [`Dashboard`][vizro.models.Dashboard] using either
-pydantic models, Python dictionaries, YAML, or JSON.
+
+This guide shows you how to configure and call a [`Dashboard`][vizro.models.Dashboard] using either pydantic models, Python dictionaries, YAML, or JSON.
To create a dashboard:
1. Choose one of the possible configuration syntaxes
-2. Create your `pages`, see our [guide on Pages](pages.md)
-3. (optional) Choose a `theme`, see our [guide on Themes](themes.md)
-4. (optional) Customize your `navigation`, see our [guide on Navigation](navigation.md)
-5. (optional) Set a `title` for your dashboard
-6. Add your `dashboard` to the `build` call of Vizro
-
+1. Create your `pages`, see our [guide on Pages](pages.md)
+1. (optional) Choose a `theme`, see our [guide on Themes](themes.md)
+1. (optional) Customize your `navigation`, see our [guide on Navigation](navigation.md)
+1. (optional) Set a `title` for your dashboard
+1. Add your `dashboard` to the `build` call of Vizro
## Use dashboard configuration options
@@ -37,6 +36,7 @@ To create a dashboard:
Vizro().build(dashboard).run()
```
+
=== "app.py - Python dict"
```py
import vizro.plotly.express as px
@@ -77,6 +77,7 @@ To create a dashboard:
Vizro().build(dashboard).run()
```
+
=== "dashboard.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -101,50 +102,49 @@ To create a dashboard:
type: filter
title: My first dashboard
```
+
=== "dashboard.json"
```json
{
- "pages": [
+ "pages": [
+ {
+ "components": [
+ {
+ "figure": {
+ "_target_": "scatter",
+ "color": "species",
+ "data_frame": "iris",
+ "x": "sepal_length",
+ "y": "petal_width"
+ },
+ "type": "graph"
+ },
{
- "components": [
- {
- "figure": {
- "_target_": "scatter",
- "color": "species",
- "data_frame": "iris",
- "x": "sepal_length",
- "y": "petal_width"
- },
- "type": "graph"
- },
- {
- "figure": {
- "_target_": "histogram",
- "color": "species",
- "data_frame": "iris",
- "x": "sepal_width",
- },
- "type": "graph"
- }
- ],
- "controls": [
- {
- "column": "species",
- "type": "filter"
- }
- ],
- "title": "My first dashboard"
+ "figure": {
+ "_target_": "histogram",
+ "color": "species",
+ "data_frame": "iris",
+ "x": "sepal_width"
+ },
+ "type": "graph"
}
- ]
+ ],
+ "controls": [
+ {
+ "column": "species",
+ "type": "filter"
+ }
+ ],
+ "title": "My first dashboard"
+ }
+ ]
}
```
- === "Result"
- [![Dashboard]][Dashboard]
- [Dashboard]: ../../assets/user_guides/dashboard/dashboard.png
+ === "Result"
+ [![Dashboard]][dashboard]
!!! note "Extra `.py` files for `yaml` and `json` required"
-
Note that in the `yaml` and `json` example an extra `.py` is required to register the data and parse the yaml/json configuration.
=== "app.py for yaml"
@@ -164,6 +164,7 @@ To create a dashboard:
Vizro().build(dashboard).run()
```
+
=== "app.py for json"
```py
import json
@@ -187,7 +188,6 @@ After running the dashboard, you can access the dashboard via `localhost:8050`.
If supplied, the `title` of the [`Dashboard`][vizro.models.Dashboard] displays a heading at the top of every page.
-
## Add a dashboard logo
Vizro will [automatically incorporate the dashboard logo](assets.md/#add-a-logo-image) in the top-left corner of each page if an image named `logo.
` is present within the assets folder.
@@ -196,11 +196,10 @@ Vizro will [automatically incorporate the dashboard logo](assets.md/#add-a-logo-
## Browser title
-The [website icon](assets.md/#change-the-favicon), Dashboard `title` (if supplied) and [Page `title`][vizro.models.Page] are displayed in the browser's
-title bar. For example, if your Dashboard `title` is "Vizro Demo" and the Page `title` is "Homepage", then the title in the browser tab will be "Vizro Demo: Homepage".
+The [website icon](assets.md/#change-the-favicon), Dashboard `title` (if supplied) and [Page `title`][vizro.models.Page] are displayed in the browser's title bar. For example, if your Dashboard `title` is "Vizro Demo" and the Page `title` is "Homepage", then the title in the browser tab will be "Vizro Demo: Homepage".
## Meta tags for social media
-Vizro automatically adds [meta tags](https://metatags.io/) to display a preview card when your app is shared on social media and chat
-clients. The preview includes the `URL`, `title`, plus an [image](assets.md/#include-a-meta-tags-image) and
-[Page `description`][vizro.models.Page] (if supplied). To see an example, try sharing an example from the [Vizro examples gallery](https://vizro.mckinsey.com/).
+Vizro automatically adds [meta tags](https://metatags.io/) to display a preview card when your app is shared on social media and chat clients. The preview includes the `URL`, `title`, plus an [image](assets.md/#include-a-meta-tags-image) and [Page `description`][vizro.models.Page] (if supplied). To see an example, try sharing an example from the [Vizro examples gallery](https://vizro.mckinsey.com/).
+
+[dashboard]: ../../assets/user_guides/dashboard/dashboard.png
diff --git a/vizro-core/docs/pages/user-guides/data.md b/vizro-core/docs/pages/user-guides/data.md
index b4fdfeda1..d19b8aafb 100644
--- a/vizro-core/docs/pages/user-guides/data.md
+++ b/vizro-core/docs/pages/user-guides/data.md
@@ -2,11 +2,12 @@
Vizro supports two different types of data:
-* [Static data](#static-data): pandas DataFrame. This is the simplest method and best to use if you do not need the more advanced functionality of dynamic data.
-* [Dynamic data](#dynamic-data): function that returns a pandas DataFrame. This is a bit more complex to understand but has more advanced functionality such as the ability to refresh data while the dashboard is running.
+- [Static data](#static-data): pandas DataFrame. This is the simplest method and best to use if you do not need the more advanced functionality of dynamic data.
+- [Dynamic data](#dynamic-data): function that returns a pandas DataFrame. This is a bit more complex to understand but has more advanced functionality such as the ability to refresh data while the dashboard is running.
The following flowchart shows what you need to consider when choosing how to set up your data.
-``` mermaid
+
+```mermaid
graph TD
refresh["`Do you need your data to refresh while the dashboard is running?`"]
specification["`Do you need to specify your dashboard through a configuration language like YAML?`"]
@@ -27,11 +28,10 @@ graph TD
```
??? note "Static vs. dynamic data comparison"
-
This table gives a full comparison between static and dynamic data. Do not worry if you do not yet understand everything in it; it will become clearer after reading more about [static data](#static-data) and [dynamic data](#dynamic-data)!
| | Static | Dynamic |
- |---------------------------------------------------------------|------------------|------------------------------------------|
+ | ------------------------------------------------------------- | ---------------- | ---------------------------------------- |
| Required Python type | pandas DataFrame | Function that returns a pandas DataFrame |
| Can be supplied directly in `data_frame` argument of `figure` | Yes | No |
| Can be referenced by name after adding to data manager | Yes | Yes |
@@ -73,14 +73,13 @@ The below example uses the Iris data saved to a file `iris.csv` in the same dire
```
1. `iris` is a pandas DataFrame created by reading from the CSV file `iris.csv`.
- === "Result"
- [![DataBasic]][DataBasic]
- [DataBasic]: ../../assets/user_guides/data/data_pandas_dataframe.png
+ === "Result"
+ [![DataBasic]][databasic]
The [`Graph`][vizro.models.Graph], [`AgGrid`][vizro.models.AgGrid] and [`Table`][vizro.models.Table] models all have an argument called `figure`. This accepts a function (in the above example, `px.scatter`) that takes a pandas DataFrame as its first argument. The name of this argument is always `data_frame`. When configuring the dashboard using Python, it is optional to give the name of the argument: if you like, you could write `data_frame=iris` instead of `iris`.
-!!! note
+!!! note
With static data, once the dashboard is running, the data shown in the dashboard cannot change even if the source data in `iris.csv` changes. The code `iris = pd.read_csv("iris.csv")` is only executed once when the dashboard is first started. If you would like changes to source data to flow through to the dashboard then you must use [dynamic data](#dynamic-data).
### Reference by name
@@ -107,27 +106,27 @@ If you would like to specify your dashboard configuration through YAML then you
```
1. `"iris"` is the name of a data source added to the data manager. This data is a pandas DataFrame created by reading from the CSV file `iris.csv`.
+
=== "dashboard.yaml"
```yaml
pages:
- - components:
- - figure:
+ - components:
+ figure:
_target_: box
data_frame: iris # (1)!
x: species
y: petal_width
color: species
type: graph
- title: Static data example
+ title: Static data example
```
1. Refer to the `"iris"` data source in the data manager.
- === "Result"
- [![DataBasic]][DataBasic]
- [DataBasic]: ../../assets/user_guides/data/data_pandas_dataframe.png
+ === "Result"
+ [![DataBasic]][databasic]
-It is also possible to refer to a named data source using the Python API: `px.scatter("iris", ...)` or `px.scatter(data_frame="iris", ...)` would work if the `"iris"` data source has been registered in the data manager.
+It is also possible to refer to a named data source using the Python API: `px.scatter("iris", ...)` or `px.scatter(data_frame="iris", ...)` would work if the `"iris"` data source has been registered in the data manager.
## Dynamic data
@@ -166,28 +165,26 @@ The example below shows how data is fetched dynamically every time the page is r
```
1. `iris` is a pandas DataFrame created by reading from the CSV file `iris.csv`.
- 2. To demonstrate that dynamic data can change when the page is refreshed, select 50 points at random. This simulates what would happen if your file `iris.csv` were constantly changing.
- 3. To use `load_iris_data` as dynamic data it must be added to the data manager. You should **not** actually call the function as `load_iris_data()`; doing so would result in static data that cannot be reloaded.
- 4. Dynamic data is referenced by the name of the data source `"iris"`.
+ 1. To demonstrate that dynamic data can change when the page is refreshed, select 50 points at random. This simulates what would happen if your file `iris.csv` were constantly changing.
+ 1. To use `load_iris_data` as dynamic data it must be added to the data manager. You should **not** actually call the function as `load_iris_data()`; doing so would result in static data that cannot be reloaded.
+ 1. Dynamic data is referenced by the name of the data source `"iris"`.
=== "Result"
- [![DynamicData]][DynamicData]
-
- [DynamicData]: ../../assets/user_guides/data/dynamic_data.gif
+ [![DynamicData]][dynamicdata]
Since dynamic data sources must always be added to the data manager and referenced by name, they may be used in YAML configuration [exactly the same way as for static data sources](#reference-by-name).
### Configure cache
-By default, each time the dashboard is refreshed a dynamic data function executes again. In fact, if there are multiple graphs on the same page using the same dynamic data source then the loading function executes _multiple_ times, once for each graph on the page. Hence, if loading your data is a slow operation, your dashboard performance may suffer.
+By default, a dynamic data function executes every time the dashboard is refreshed. Data loading is batched so that a dynamic data function that supplies multiple graphs on the same page only executes _once_ per page refresh. Even with this batching, if loading your data is a slow operation, your dashboard performance may suffer.
The Vizro data manager has a server-side caching mechanism to help solve this. Vizro's cache uses [Flask-Caching](https://flask-caching.readthedocs.io/en/latest/), which supports a number of possible cache backends and [configuration options](https://flask-caching.readthedocs.io/en/latest/#configuring-flask-caching). By default, the cache is turned off.
+
In a development environment the easiest way to enable caching is to use a [simple memory cache](https://cachelib.readthedocs.io/en/stable/simple/) with the default configuration options. This is achieved by adding one line to the above example to set `data_manager.cache`:
!!! example "Simple cache with default timeout of 5 minutes"
-
```py hl_lines="13"
from flask_caching import Cache
from vizro import Vizro
@@ -220,12 +217,11 @@ By default, when caching is turned on, dynamic data is cached in the data manage
If you would like to alter some options, such as the default cache timeout, then you can specify a different cache configuration:
-```py title="Simple cache with timeout set to 10 minutes"
+```python title="Simple cache with timeout set to 10 minutes"
data_manager.cache = Cache(config={"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_TIMEOUT": 600})
```
!!! warning
-
Simple cache exists purely for single-process development purposes and is not intended to be used in production. If you deploy with multiple workers, [for example with Gunicorn](run.md/#gunicorn), then you should use a production-ready cache backend. All of Flask-Caching's [built-in backends](https://flask-caching.readthedocs.io/en/latest/#built-in-cache-backends) other than `SimpleCache` are suitable for production. In particular, you might like to use [`FileSystemCache`](https://cachelib.readthedocs.io/en/stable/file/) or [`RedisCache`](https://cachelib.readthedocs.io/en/stable/redis/):
```py title="Production-ready caches"
@@ -239,7 +235,9 @@ data_manager.cache = Cache(config={"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_T
Since Flask-Caching relies on [`pickle`](https://docs.python.org/3/library/pickle.html), which can execute arbitrary code during unpickling, you should not cache data from untrusted sources. Doing so [could be unsafe](https://github.com/pallets-eco/flask-caching/pull/209).
Note that when a production-ready cache backend is used, the cache is persisted beyond the Vizro process and is not cleared by restarting your server. To clear the cache then you must do so manually, for example, if you use `FileSystemCache` then you would delete your `cache` directory. Persisting the cache can also be useful for development purposes when handling data that takes a long time to load: even if you do not need the data to refresh while your dashboard is running, it can speed up your development loop to use dynamic data with a cache that is persisted between repeated runs of Vizro.
+
+
#### Set timeouts
You can change the timeout of the cache independently for each dynamic data source in the data manager using the `timeout` setting (measured in seconds). A `timeout` of 0 indicates that the cache does not expire. This is effectively the same as using [static data](#static-data).
@@ -268,16 +266,20 @@ data_manager["no_expire_data"].timeout = 0
### Parametrize data loading
-You can supply arguments to your dynamic data loading function that can be modified from the dashboard.
-For example, if you are handling big data then you can use an argument to specify the number of entries or size of chunk of data.
+You can give arguments to your dynamic data loading function that can be modified from the dashboard. For example:
+
+- To load different versions of the same data.
+- To handle large datasets you can use an argument that controls the amount of data that is loaded. This effectively pre-filters data before it reaches the Vizro dashboard.
+
+In general, a parametrized dynamic data source should always return a pandas DataFrame with a fixed schema (column names and types). This ensures that page components and controls continue to work as expected when the parameter is changed on screen.
To add a parameter to control a dynamic data source, do the following:
1. add the appropriate argument to your dynamic data function and specify a default value for the argument.
-2. give an `id` to all components that have the data source you wish to alter through a parameter.
-3. [add a parameter](parameters.md) with `targets` of the form `.data_frame.` and a suitable [selector](selectors.md).
+1. give an `id` to all components that have the data source you wish to alter through a parameter.
+1. [add a parameter](parameters.md) with `targets` of the form `.data_frame.` and a suitable [selector](selectors.md).
-For example, let us extend the [dynamic data example](#dynamic-data) above to show how the `load_iris_data` can take an argument `number_of_points` controlled from the dashboard with a [`Slider`][vizro.models.Slider].
+For example, let us extend the [dynamic data example](#dynamic-data) above into an example of how parametrized dynamic data works. The `load_iris_data` can take an argument `number_of_points` controlled from the dashboard with a [`Slider`][vizro.models.Slider].
!!! example "Parametrized dynamic data"
=== "app.py"
@@ -314,33 +316,100 @@ For example, let us extend the [dynamic data example](#dynamic-data) above to sh
```
1. `load_iris_data` takes a single argument, `number_of_points`, with a default value of 10.
- 2. `iris` is a pandas DataFrame created by reading from the CSV file `iris.csv`.
- 3. Sample points at random, where `number_of_points` gives the number of points selected.
- 4. To use `load_iris_data` as dynamic data it must be added to the data manager. You should **not** actually call the function as `load_iris_data()` or `load_iris_data(number_of_points=...)`; doing so would result in static data that cannot be reloaded.
- 5. Give the `vm.Graph` component `id="graph"` so that the `vm.Parameter` can target it. Dynamic data is referenced by the name of the data source `"iris"`.
- 6. Create a `vm.Parameter` to target the `number_of_points` argument for the `data_frame` used in `graph`.
+ 1. `iris` is a pandas DataFrame created by reading from the CSV file `iris.csv`.
+ 1. Sample points at random, where `number_of_points` gives the number of points selected.
+ 1. To use `load_iris_data` as dynamic data it must be added to the data manager. You should **not** actually call the function as `load_iris_data()` or `load_iris_data(number_of_points=...)`; doing so would result in static data that cannot be reloaded.
+ 1. Give the `vm.Graph` component `id="graph"` so that the `vm.Parameter` can target it. Dynamic data is referenced by the name of the data source `"iris"`.
+ 1. Create a `vm.Parameter` to target the `number_of_points` argument for the `data_frame` used in `graph`.
=== "Result"
- [![ParametrizedDynamicData]][ParametrizedDynamicData]
-
- [ParametrizedDynamicData]: ../../assets/user_guides/data/parametrized_dynamic_data.gif
+ [![ParametrizedDynamicData]][parametrizeddynamicdata]
Parametrized data loading is compatible with [caching](#configure-cache). The cache uses [memoization](https://flask-caching.readthedocs.io/en/latest/#memoization), so that the dynamic data function's arguments are included in the cache key. This means that `load_iris_data(number_of_points=10)` is cached independently of `load_iris_data(number_of_points=20)`.
!!! warning
-
You should always [treat the content of user input as untrusted](https://community.plotly.com/t/writing-secure-dash-apps-community-thread/54619). For example, you should not expose a filepath to load without passing it through a function like [`werkzeug.utils.secure_filename`](https://werkzeug.palletsprojects.com/en/3.0.x/utils/#werkzeug.utils.secure_filename), or you might enable arbitrary access to files on your server.
You cannot pass [nested parameters](parameters.md#nested-parameters) to dynamic data. You can only target the top-level arguments of the data loading function, not the nested keys in a dictionary.
-### Filter update limitation
+### Filters
+
+When a [filter](filters.md) depends on dynamic data and no `selector` is explicitly defined in the `vm.Filter` model, the available selector values update on page refresh to reflect the latest dynamic data. This is called a _dynamic filter_.
+
+The mechanism behind updating dynamic filters works exactly like other non-control components such as `vm.Graph`. However, unlike such components, a filter can depend on multiple data sources. If at least one data source of the components in the filter's `targets` is dynamic then the filter is dynamic. Remember that when `targets` is not explicitly specified, a filter applies to all the components on a page that use a DataFrame including `column`.
+
+When the page is refreshed, the behavior of a dynamic filter is as follows:
+
+- The filter's selector updates its available values:
+ - For [categorical selectors](selectors.md#categorical-selectors), `options` updates to give all unique values found in `column` across all the data sources of components in `targets`.
+ - For [numerical selectors](selectors.md#numerical-selectors), `min` and `max` update to give the overall minimum and maximum values found in `column` across all the data sources of components in `targets`.
+- The value selected on screen by a dashboard user _does not_ change. If the selected value is not already present in the new set of available values then the `options` or `min` and `max` are modified to include it. In this case, the filtering operation might result in an empty DataFrame.
+- Even though the values present in a data source can change, the schema should not: `column` should remain present and of the same type in the data sources. The `targets` of the filter and selector type cannot change while the dashboard is running. For example, a `vm.Dropdown` selector cannot turn into `vm.RadioItems`.
+
+For example, let us add two filters to the [dynamic data example](#dynamic-data) above:
+
+!!! example "Dynamic filters"
+ ```py hl_lines="10 20 21"
+ from vizro import Vizro
+ import pandas as pd
+ import vizro.plotly.express as px
+ import vizro.models as vm
+
+ from vizro.managers import data_manager
+
+ def load_iris_data():
+ iris = pd.read_csv("iris.csv")
+ return iris.sample(5) # (1)!
+
+ data_manager["iris"] = load_iris_data
+
+ page = vm.Page(
+ title="Update the chart and filters on page refresh",
+ components=[
+ vm.Graph(figure=px.box("iris", x="species", y="petal_width", color="species"))
+ ],
+ controls=[
+ vm.Filter(column="species"), # (2)!
+ vm.Filter(column="sepal_length"), # (3)!
+ ],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+
+ Vizro().build(dashboard).run()
+ ```
+
+ 1. We sample only 5 rather than 50 points so that changes to the available values in the filtered columns are more apparent when the page is refreshed.
+ 1. This filter implicitly controls the dynamic data source `"iris"`, which supplies the `data_frame` to the targeted `vm.Graph`. On page refresh, Vizro reloads this data, finds all the unique values in the `"species"` column and sets the categorical selector's `options` accordingly.
+ 1. Similarly, on page refresh, Vizro finds the minimum and maximum values of the `"sepal_length"` column in the reloaded data and sets new `min` and `max` values for the numerical selector accordingly.
-If your dashboard includes a [filter](filters.md) then the values shown on a filter's [selector](selectors.md) _do not_ update while the dashboard is running. This is a known limitation that will be lifted in future releases, but if is problematic for you already then [raise an issue on our GitHub repo](https://github.com/mckinsey/vizro/issues/).
+Consider a filter that depends on dynamic data, where you do **not** want the available values to change when the dynamic data changes. You should manually specify the `selector`'s `options` field (categorical selector) or `min` and `max` fields (numerical selector). In the above example, this could be achieved as follows:
-This limitation is why all arguments of your dynamic data loading function must have a default value. Regardless of the value of the `vm.Parameter` selected in the dashboard, these default parameter values are used when the `vm.Filter` is built. This determines the type of selector used in a filter and the options shown, which cannot currently be changed while the dashboard is running.
+```python title="Override selector options to make a dynamic filter static"
+controls = [
+ vm.Filter(column="species", selector=vm.Dropdown(options=["setosa", "versicolor", "virginica"])),
+ vm.Filter(column="sepal_length", selector=vm.RangeSlider(min=4.3, max=7.9)),
+]
+```
-Although a selector is automatically chosen for you in a filter when your dashboard is built, remember that [you can change this choice](filters.md#changing-selectors). For example, we could ensure that a dropdown always contains the options "setosa", "versicolor" and "virginica" by explicitly specifying your filter as follows.
+If you [use a specific selector](filters.md#change-selector) for a dynamic filter without manually specifying `options` (categorical selector) or `min` and `max` (numerical selector) then the selector remains dynamic. For example:
-```py
-vm.Filter(column="species", selector=vm.Dropdown(options=["setosa", "versicolor", "virginica"])
+```python title="Dynamic filter with specific selector is still dynamic"
+controls = [
+ vm.Filter(column="species", selector=vm.Checklist()),
+ vm.Filter(column="sepal_length", selector=vm.Slider()),
+]
```
+
+When Vizro initially builds a filter that depends on parametrized dynamic data loading, data is loaded using the default argument values. This data is used to:
+
+- perform initial validation
+- check which data sources contain the specified `column` (unless `targets` is explicitly specified) and
+- find the type of selector to use (unless `selector` is explicitly specified).
+
+!!! note
+ When the value of a dynamic data parameter is changed by a dashboard user, the data underlying a dynamic filter can change. Currently this change affects page components such as `vm.Graph` but does not affect the available values shown in a dynamic filter, which only update on page refresh. This functionality will be coming soon!
+
+[databasic]: ../../assets/user_guides/data/data_pandas_dataframe.png
+[dynamicdata]: ../../assets/user_guides/data/dynamic_data.gif
+[parametrizeddynamicdata]: ../../assets/user_guides/data/parametrized_dynamic_data.gif
diff --git a/vizro-core/docs/pages/user-guides/extensions.md b/vizro-core/docs/pages/user-guides/extensions.md
index 2c7efc9ac..74a740448 100644
--- a/vizro-core/docs/pages/user-guides/extensions.md
+++ b/vizro-core/docs/pages/user-guides/extensions.md
@@ -2,64 +2,49 @@
At its simplest, Vizro enables low-code configuration, but you can also customize it to go beyond its default capabilities by incorporating any Dash component, Dash callback, or Plotly chart.
-* **[Vizro customizations](#vizro-customizations)**. You can customize Vizro to extend the default functionality of Vizro and create Python functions as customized Plotly charts, tables, dashboard components, actions, or reactive HTML components, and then plug them directly into the existing Vizro dashboard configuration (as explained below).
+- **[Vizro customizations](#vizro-customizations)**. You can customize Vizro to extend the default functionality of Vizro and create Python functions as customized Plotly charts, tables, dashboard components, actions, or reactive HTML components, and then plug them directly into the existing Vizro dashboard configuration (as explained below).
-* **[Dash customizations](#dash-customizations)**. You can add custom Dash callbacks directly to any Vizro dashboard, enabling you to code beneath the Vizro layer and control Dash directly.
+- **[Dash customizations](#dash-customizations)**. You can add custom Dash callbacks directly to any Vizro dashboard, enabling you to code beneath the Vizro layer and control Dash directly.
-* **[CSS customizations](#css-customizations)**. You can add custom CSS to any Vizro dashboard, enabling users to deviate from the default styling and create a unique look and feel for their dashboard.
-
-* **[React.js customizations](#reactjs-customizations)**. You can add custom React.js components directly to any Vizro dashboard, enabling users to go beneath both the Vizro and Dash layers and control React.js directly
+- **[CSS customizations](#css-customizations)**. You can add custom CSS to any Vizro dashboard, enabling users to deviate from the default styling and create a unique look and feel for their dashboard.
+- **[React.js customizations](#reactjs-customizations)**. You can add custom React.js components directly to any Vizro dashboard, enabling users to go beneath both the Vizro and Dash layers and control React.js directly
Vizro offers the ability to combine ease of use of low-code configuration, with the flexibility of a range of high-code extensions to expand your dashboard's functionality.
-
## Vizro customizations
### [Custom charts](custom-charts.md)
-You can create custom chart functions in Vizro by wrapping Plotly chart code inside a
-Vizro chart function wrapper, and then use the functions directly inside the Vizro dashboard configuration. This enables the creation of `plotly.graph_objects` charts with multiple traces, or `plotly_express` charts with post update customizations
-
+You can create custom chart functions in Vizro by wrapping Plotly chart code inside a Vizro chart function wrapper, and then use the functions directly inside the Vizro dashboard configuration. This enables the creation of `plotly.graph_objects` charts with multiple traces, or `plotly_express` charts with post update customizations
### [Custom tables](custom-tables.md)
If the available arguments for the [`dash_ag_grid`][vizro.tables.dash_ag_grid] or [`dash_data_table`][vizro.tables.dash_data_table] models are insufficient, you can create a custom Dash AG Grid or Dash DataTable.
-
### [Custom components](custom-components.md)
-You can create a custom component based on any dash-compatible component (for example, [dash-core-components](https://dash.plotly.com/dash-core-components),
-[dash-bootstrap-components](https://dash-bootstrap-components.opensource.faculty.ai/), [dash-html-components](https://github.com/plotly/dash/tree/dev/components/dash-html-components)).
+You can create a custom component based on any dash-compatible component (for example, [dash-core-components](https://dash.plotly.com/dash-core-components), [dash-bootstrap-components](https://dash-bootstrap-components.opensource.faculty.ai/), [dash-html-components](https://github.com/plotly/dash/tree/dev/components/dash-html-components)).
All Vizro's components are based on `Dash` and ship with a set of defaults that can be modified. If you would like to overwrite one of those defaults, or if you would like to use extra `args` or `kwargs` of those components, then this is the correct way to include those. You can use any existing attribute of any underlying [Dash component](https://dash.plotly.com/#open-source-component-libraries) with this method.
-
### [Custom actions](custom-actions.md)
-If you want to use the [`Action`][vizro.models.Action] model to perform functions that are not available in the [pre-defined action functions][vizro.actions], you can create your own custom action.
-Like other [actions](actions.md), custom actions can also be added as an element inside the [actions chain](actions.md#chain-actions), and triggered with one of dashboard components.
-
+If you want to use the [`Action`][vizro.models.Action] model to perform functions that are not available in the [pre-defined action functions][vizro.actions], you can create your own custom action. Like other [actions](actions.md), custom actions can also be added as an element inside the [actions chain](actions.md#chain-actions), and triggered with one of dashboard components.
### [Custom figures](custom-figures.md)
-Custom figures are useful when you need a component that reacts to
-[filter](filters.md) and [parameter](parameters.md) controls.
-
-Vizro's [`Figure`][vizro.models.Figure] model accepts the `figure` argument, where you can enter _any_ custom figure function
-as described in the [how-to guide for figures](figure.md).
+Custom figures are useful when you need a component that reacts to [filter](filters.md) and [parameter](parameters.md) controls.
+Vizro's [`Figure`][vizro.models.Figure] model accepts the `figure` argument, where you can enter _any_ custom figure function as described in the [how-to guide for figures](figure.md).
## Dash customizations
-Since Vizro is built using Dash, it is possible to use [Dash callbacks](https://dash.plotly.com/basic-callbacks) directly in any Vizro dashboard. This enables you to code beneath the Vizro layer and control Dash directly,
-which is especially useful when working with callbacks
+Since Vizro is built using Dash, it is possible to use [Dash callbacks](https://dash.plotly.com/basic-callbacks) directly in any Vizro dashboard. This enables you to code beneath the Vizro layer and control Dash directly, which is especially useful when working with callbacks
-Here is an example showing a Dash callback within Vizro,
-enabling an interaction between data points in a scatter plot and the content of a text card:
+Here is an example showing a Dash callback within Vizro, enabling an interaction between data points in a scatter plot and the content of a text card:
!!! example "Dash callback example"
-
=== "app.py"
```{.python pycafe-link}
from dash import callback, Input, Output
@@ -93,14 +78,12 @@ enabling an interaction between data points in a scatter plot and the content of
## CSS customizations
-Vizro is opinionated about visual formatting, and some elements, such as the layout of the navigation and controls,
-are fixed. You can customize some settings such as background colors, fonts, and other styles via CSS overrides.
+Vizro is opinionated about visual formatting, and some elements, such as the layout of the navigation and controls, are fixed. You can customize some settings such as background colors, fonts, and other styles via CSS overrides.
For more information, see our documentation on [customizing CSS](custom-css.md)
## React.js customizations
-It is possible to create custom React.js components and add them
-directly to any Vizro dashboard so enabling you to code beneath both the Vizro and Dash layers and control React.js directly
+It is possible to create custom React.js components and add them directly to any Vizro dashboard so enabling you to code beneath both the Vizro and Dash layers and control React.js directly
For more information, see the documentation on [using React.js components with Dash](https://dash.plotly.com/plugins)
diff --git a/vizro-core/docs/pages/user-guides/figure.md b/vizro-core/docs/pages/user-guides/figure.md
index 0589fad3b..03bfa412a 100644
--- a/vizro-core/docs/pages/user-guides/figure.md
+++ b/vizro-core/docs/pages/user-guides/figure.md
@@ -1,26 +1,19 @@
# How to use figures
-This guide shows you how to add any [Dash component](https://dash.plotly.com/#open-source-component-libraries) that needs to be reactive to [filter](filters.md) and [parameter](parameters.md) controls.
-If you want to add a static Dash component to your page, use [custom components](custom-components.md) instead.
+This guide shows you how to add any [Dash component](https://dash.plotly.com/#open-source-component-libraries) that needs to be reactive to [filter](filters.md) and [parameter](parameters.md) controls. If you want to add a static Dash component to your page, use [custom components](custom-components.md) instead.
-[`Figure`][vizro.models.Figure] provides a flexible foundation for all types of reactive Dash components in Vizro.
-The [`Graph`][vizro.models.Graph], [`Table`][vizro.models.Table] and [`AgGrid`][vizro.models.AgGrid] components are
-specific implementations of `Figure`. They serve as intuitive shortcuts, embedding behaviors and interactions specific
-to their purposes.
+[`Figure`][vizro.models.Figure] provides a flexible foundation for all types of reactive Dash components in Vizro. The [`Graph`][vizro.models.Graph], [`Table`][vizro.models.Table] and [`AgGrid`][vizro.models.AgGrid] components are specific implementations of `Figure`. They serve as intuitive shortcuts, embedding behaviors and interactions specific to their purposes.
-If these more specific models already achieve what you need then they should be used in preference to
-the more generic `Figure`. Remember that it is possible to supply [custom charts](custom-charts.md) to `Graph`
-and [custom tables](custom-tables.md) to `Table`.
+If these more specific models already achieve what you need then they should be used in preference to the more generic `Figure`. Remember that it is possible to supply [custom charts](custom-charts.md) to `Graph` and [custom tables](custom-tables.md) to `Table`.
-There are already a few figure functions you can reuse, see the section on [KPI cards](#key-performance-indicator-kpi-cards)
-for more details:
+There are already a few figure functions you can reuse, see the section on [KPI cards](#key-performance-indicator-kpi-cards) for more details:
- [`kpi_card`][vizro.figures.kpi_card]
- [`kpi_card_reference`][vizro.figures.kpi_card_reference]
The following flowchart shows what you need to consider when choosing which model to use:
-``` mermaid
+```mermaid
graph TD
first["`Does your desired component exist in Vizro, e.g. Graph, Table or AgGrid?`"]
specific-component([Use the specific component])
@@ -40,14 +33,12 @@ graph TD
classDef clickable color:#4051b5;
```
-
To add a `Figure` to your page:
1. Add the `Figure` model to the components argument of the [Page][vizro.models.Page] model.
-2. Use an existing figure function from [`vizro.figures`](../API-reference/figure-callables.md) and pass it to the `figure` argument of the `Figure` model.
+1. Use an existing figure function from [`vizro.figures`](../API-reference/figure-callables.md) and pass it to the `figure` argument of the `Figure` model.
!!! example "Use existing figure functions"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -99,40 +90,25 @@ To add a `Figure` to your page:
selector:
type: radio_items
layout:
- grid:
- [
- [0, -1, -1, -1],
- [-1, -1, -1, -1],
- [-1, -1, -1, -1],
- [-1, -1, -1, -1],
- [-1, -1, -1, -1],
- ]
+ grid: [[0, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1],
+ [-1, -1, -1, -1]]
title: KPI card
```
- === "Result"
- [![Figure]][Figure]
-
- [Figure]: ../../assets/user_guides/figure/figure.png
+ === "Result"
+ [![Figure]][figure]
### Key Performance Indicator (KPI) cards
-A KPI card is a dynamic card that can display a single value, but optionally, can also include a title, icon, and reference value.
-It is a common visual component to display key metrics in a dashboard. Vizro supports two pre-defined KPI card functions:
-- [`kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card): A KPI card that shows a single value found
-by performing an aggregation function (by default, `sum`) over a specified column.
-Required arguments are `data_frame` and `value_column`.
+A KPI card is a dynamic card that can display a single value, but optionally, can also include a title, icon, and reference value. It is a common visual component to display key metrics in a dashboard. Vizro supports two pre-defined KPI card functions:
-- [`kpi_card_with_reference`](../API-reference/figure-callables.md#vizro.figures.kpi_card_reference): A KPI card that shows a single value
-and a delta comparison to a reference value found by performing an aggregation function (by default, `sum`) over the specified columns.
-Required arguments are `data_frame`, `value_column` and `reference_column`.
+- [`kpi_card`](../API-reference/figure-callables.md#vizro.figures.kpi_card): A KPI card that shows a single value found by performing an aggregation function (by default, `sum`) over a specified column. Required arguments are `data_frame` and `value_column`.
-As described in the [API reference](../API-reference/figure-callables.md) and illustrated in the below example, these
-functions have several arguments to customize your KPI cards. If you require a level of customization that is not
-possible with the built-in functions then you can create a [custom figure](custom-figures.md).
+- [`kpi_card_with_reference`](../API-reference/figure-callables.md#vizro.figures.kpi_card_reference): A KPI card that shows a single value and a delta comparison to a reference value found by performing an aggregation function (by default, `sum`) over the specified columns. Required arguments are `data_frame`, `value_column` and `reference_column`.
-!!! example "KPI card variations"
+As described in the [API reference](../API-reference/figure-callables.md) and illustrated in the below example, these functions have several arguments to customize your KPI cards. If you require a level of customization that cannot be done with the built-in functions then you can create a [custom figure](custom-figures.md).
+!!! example "KPI card variations"
=== "app.py"
```{.python pycafe-link}
import pandas as pd
@@ -258,8 +234,8 @@ possible with the built-in functions then you can create a [custom figure](custo
value_column: Actual
reference_column: Reference
title: KPI reference with formatting
- value_format: "{value:.2f}€"
- reference_format: "{delta:+.2f}€ vs. last year ({reference:.2f}€)"
+ value_format: '{value:.2f}€'
+ reference_format: '{delta:+.2f}€ vs. last year ({reference:.2f}€)'
type: figure
- figure:
_target_: kpi_card_reference
@@ -276,7 +252,9 @@ possible with the built-in functions then you can create a [custom figure](custo
grid: [[0, 1, 2, 3], [4, 5, 6, 7], [-1, -1, -1, -1], [-1, -1, -1, -1]]
title: KPI cards
```
+
=== "Result"
- [![KPICards]][KPICards]
+ [![KPICards]][kpicards]
- [KPICards]: ../../assets/user_guides/figure/kpi_cards.png
+[figure]: ../../assets/user_guides/figure/figure.png
+[kpicards]: ../../assets/user_guides/figure/kpi_cards.png
diff --git a/vizro-core/docs/pages/user-guides/filters.md b/vizro-core/docs/pages/user-guides/filters.md
index e5dd2ed61..8228ecbe7 100644
--- a/vizro-core/docs/pages/user-guides/filters.md
+++ b/vizro-core/docs/pages/user-guides/filters.md
@@ -2,19 +2,18 @@
This guide shows you how to add filters to your dashboard. One main way to interact with the charts/components on your page is by filtering the underlying data. A filter selects a subset of rows of a component's underlying DataFrame which alters the appearance of that component on the page.
-The [`Page`][vizro.models.Page] model accepts the `controls` argument, where you can enter a [`Filter`][vizro.models.Filter] model.
-This model enables the automatic creation of [selectors](../user-guides/selectors.md) (such as Dropdown, RadioItems, Slider, ...) that operate upon the charts/components on the screen.
+The [`Page`][vizro.models.Page] model accepts the `controls` argument, where you can enter a [`Filter`][vizro.models.Filter] model. This model enables the automatic creation of [selectors](selectors.md) (for example, `Dropdown` or `RangeSlider`) that operate on the charts/components on the screen.
+By default, filters that control components with [dynamic data](data.md#dynamic-data) are [dynamically updated](data.md#filters) when the underlying data changes while the dashboard is running.
## Basic filters
To add a filter to your page, do the following:
1. add the [`Filter`][vizro.models.Filter] model into the `controls` argument of the [`Page`][vizro.models.Page] model
-2. configure the `column` argument, which denotes the target column to be filtered
+1. configure the `column` argument, which denotes the target column to be filtered
-By default, all components on a page with such a `column` present will be filtered. The selector type will be chosen
-automatically based on the target column, for example, a dropdown for categorical data, a range slider for numerical data, or a date picker for temporal data.
+You can also set `targets` to specify which components on the page the filter should apply to. If this is not explicitly set then `targets` defaults to all components on the page whose data source includes `column`.
!!! example "Basic Filter"
=== "app.py"
@@ -39,6 +38,7 @@ automatically based on the target column, for example, a dropdown for categorica
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -57,18 +57,86 @@ automatically based on the target column, for example, a dropdown for categorica
type: filter
title: My first page
```
+
=== "Result"
+ [![Filter]][filter]
- [![Filter]][Filter]
+The selector is configured automatically based on the target column type data as follows:
- [Filter]: ../../assets/user_guides/control/control1.png
+- Categorical data uses [`vm.Dropdown(multi=True)`][vizro.models.Dropdown] where `options` is the set of unique values found in `column` across all the data sources of components in `targets`.
+- [Numerical data](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_numeric_dtype.html) uses [`vm.RangeSlider`][vizro.models.RangeSlider] where `min` and `max` are the overall minimum and maximum values found in `column` across all the data sources of components in `targets`.
+- [Temporal data](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_datetime64_any_dtype.html) uses [`vm.DatePicker(range=True)`][vizro.models.DatePicker] where `min` and `max` are the overall minimum and maximum values found in `column` across all the data sources of components in `targets`. A column can be converted to this type with [pandas.to_datetime](https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html).
-## Changing selectors
+The following example demonstrates these default selector types.
-If you want to have a different selector for your filter, you can give the `selector` argument of the [`Filter`][vizro.models.Filter] a different selector model.
-Currently available selectors are [`Checklist`][vizro.models.Checklist], [`Dropdown`][vizro.models.Dropdown], [`RadioItems`][vizro.models.RadioItems], [`RangeSlider`][vizro.models.RangeSlider], [`Slider`][vizro.models.Slider], and [`DatePicker`][vizro.models.DatePicker].
+!!! example "Default Filter selectors"
+ === "app.py"
+ ```{.python pycafe-link}
+ import pandas as pd
+ from vizro import Vizro
+ import vizro.plotly.express as px
+ import vizro.models as vm
-!!! example "Filter with custom Selector"
+ df_stocks = px.data.stocks(datetimes=True)
+
+ df_stocks_long = pd.melt(
+ df_stocks,
+ id_vars='date',
+ value_vars=['GOOG', 'AAPL', 'AMZN', 'FB', 'NFLX', 'MSFT'],
+ var_name='stocks',
+ value_name='value'
+ )
+
+ df_stocks_long['value'] = df_stocks_long['value'].round(3)
+
+ page = vm.Page(
+ title="My first page",
+ components=[
+ vm.Graph(figure=px.line(df_stocks_long, x="date", y="value", color="stocks")),
+ ],
+ controls=[
+ vm.Filter(column="stocks"),
+ vm.Filter(column="value"),
+ vm.Filter(column="date"),
+ ],
+ )
+
+ dashboard = vm.Dashboard(pages=[page])
+
+ Vizro().build(dashboard).run()
+ ```
+
+ === "app.yaml"
+ ```yaml
+ # Still requires a .py to add data to the data manager and parse YAML configuration
+ # See yaml_version example
+ pages:
+ - components:
+ - figure:
+ _target_: line
+ data_frame: df_stocks_long
+ x: date
+ y: value
+ color: stocks
+ type: graph
+ controls:
+ - column: stocks
+ type: filter
+ - column: value
+ type: filter
+ - column: date
+ type: filter
+ title: My first page
+ ```
+
+ === "Result"
+ [![Filter]][filter]
+
+## Change selector
+
+If you want to have a different selector for your filter, you can give the `selector` argument of the [`Filter`][vizro.models.Filter] a different selector model. Currently available selectors are [`Checklist`][vizro.models.Checklist], [`Dropdown`][vizro.models.Dropdown], [`RadioItems`][vizro.models.RadioItems], [`RangeSlider`][vizro.models.RangeSlider], [`Slider`][vizro.models.Slider], and [`DatePicker`][vizro.models.DatePicker].
+
+!!! example "Filter with different selector"
=== "app.py"
```{.python pycafe-link}
from vizro import Vizro
@@ -91,6 +159,7 @@ Currently available selectors are [`Checklist`][vizro.models.Checklist], [`Dropd
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -110,19 +179,16 @@ Currently available selectors are [`Checklist`][vizro.models.Checklist], [`Dropd
type: filter
title: My first page
```
- === "Result"
-
- [![Selector]][Selector]
- [Selector]: ../../assets/user_guides/control/control2.png
+ === "Result"
+ [![Selector]][selector]
## Further customization
-For further customizations, you can always refer to the [`Filter`][vizro.models.Filter] reference. Some popular choices are:
+For further customizations, you can always refer to the [`Filter` model][vizro.models.Filter] reference and the [guide to selectors](selectors.md). Some popular choices are:
- select which component the filter will apply to by using `targets`
-- select what the target column type is, hence choosing the default selector by using `column_type`
-- choose options of lower level components, such as the `selector` models
+- specify configuration of the `selector`, for example `multi` to switch between a multi-option and single-option selector, `options` for a categorical filter or `min` and `max` for a numerical filter
Below is an advanced example where we only target one page component, and where we further customize the chosen `selector`.
@@ -139,10 +205,10 @@ Below is an advanced example where we only target one page component, and where
title="My first page",
components=[
vm.Graph(id="scatter_chart", figure=px.scatter(iris, x="sepal_length", y="petal_width", color="species")),
- vm.Graph(id="scatter_chart2", figure=px.scatter(iris, x="petal_length", y="sepal_width", color="species")),
+ vm.Graph(figure=px.scatter(iris, x="petal_length", y="sepal_width", color="species")),
],
controls=[
- vm.Filter(column="petal_length",targets=["scatter_chart"],selector=vm.RangeSlider(step=1)),
+ vm.Filter(column="petal_length",targets=["scatter_chart"], selector=vm.RangeSlider(step=1)),
],
)
@@ -150,6 +216,7 @@ Below is an advanced example where we only target one page component, and where
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -170,20 +237,23 @@ Below is an advanced example where we only target one page component, and where
x: petal_length
y: sepal_width
color: species
- id: scatter_chart2
type: graph
controls:
- column: petal_length
targets:
- - scatter_chart
+ - scatter_chart
selector:
step: 1
type: range_slider
type: filter
title: My first page
```
+
=== "Result"
+ [![Advanced]][advanced]
- [![Advanced]][Advanced]
+To further customize selectors, see our [how-to-guide on creating custom components](custom-components.md).
- [Advanced]: ../../assets/user_guides/control/control3.png
+[advanced]: ../../assets/user_guides/control/control3.png
+[filter]: ../../assets/user_guides/control/control1.png
+[selector]: ../../assets/user_guides/control/control2.png
diff --git a/vizro-core/docs/pages/user-guides/graph.md b/vizro-core/docs/pages/user-guides/graph.md
index 36c670997..1c3ffc8bc 100755
--- a/vizro-core/docs/pages/user-guides/graph.md
+++ b/vizro-core/docs/pages/user-guides/graph.md
@@ -6,25 +6,18 @@ The [`Graph`][vizro.models.Graph] model is the most used component in many dashb
To add a [`Graph`][vizro.models.Graph] to your page, do the following:
-1. insert the [`Graph`][vizro.models.Graph] model into the `components` argument of the
-[`Page`][vizro.models.Page] model
-2. enter any of the currently available charts of the open source library [`plotly.express`](https://plotly.com/python/plotly-express/) into the `figure` argument
+1. insert the [`Graph`][vizro.models.Graph] model into the `components` argument of the [`Page`][vizro.models.Page] model
+1. enter any of the currently available charts of the open source library [`plotly.express`](https://plotly.com/python/plotly-express/) into the `figure` argument
!!! note
+ To use the [`plotly.express`](https://plotly.com/python/plotly-express/) chart in a Vizro dashboard, you need to import it as `import vizro.plotly.express as px`. This leaves any of the [`plotly.express`](https://plotly.com/python/plotly-express/) functionality untouched yet enables _direct insertion_ into the [`Graph`][vizro.models.Graph] model _as is_.
- In order to use the [`plotly.express`](https://plotly.com/python/plotly-express/) chart in a Vizro dashboard, you need to import it as `import vizro.plotly.express as px`.
- This leaves any of the [`plotly.express`](https://plotly.com/python/plotly-express/) functionality untouched, but allows _direct insertion_ into the [`Graph`][vizro.models.Graph] model _as is_.
-
- Note also that the `plotly.express` chart needs to have a `data_frame` argument. In case you require a chart without
- a `data_frame` argument (for example, the [`imshow` chart](https://plotly.com/python/imshow/)), refer to our
- [guide on custom charts](custom-charts.md).
-
+ Note also that the `plotly.express` chart needs to have a `data_frame` argument. In case you require a chart without a `data_frame` argument (for example, the [`imshow` chart](https://plotly.com/python/imshow/)), refer to our [guide on custom charts](custom-charts.md).
## Insert Plotly chart
!!! example "Graph"
=== "app.py"
-
```{.python pycafe-link}
import vizro.models as vm
import vizro.plotly.express as px
@@ -47,25 +40,24 @@ To add a [`Graph`][vizro.models.Graph] to your page, do the following:
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: scatter_matrix
- color: species
- data_frame: iris
- dimensions: ["sepal_length", "sepal_width", "petal_length", "petal_width"]
- type: graph
- title: My first page
+ - components:
+ - figure:
+ _target_: scatter_matrix
+ color: species
+ data_frame: iris
+ dimensions: [sepal_length, sepal_width, petal_length, petal_width]
+ type: graph
+ title: My first page
```
- === "Result"
- [![Graph]][Graph]
-
- [Graph]: ../../assets/user_guides/components/graph.png
+ === "Result"
+ [![Graph]][graph]
In the Python example we directly inserted the pandas DataFrame `df` into `figure=px.scatter_matrix(df, ...)`. This is [one way to supply data to a chart](data.md#supply-directly). For the YAML version, we [refer to the data source by name](data.md#reference-by-name) as `data_frame: iris`. For a full explanation of the different methods you can use to send data to your dashboard, see [our guide to using data in Vizro](data.md).
@@ -73,31 +65,24 @@ In the Python example we directly inserted the pandas DataFrame `df` into `figur
You will need to create a custom chart if you want to customize the Plotly chart beyond a function call, for example by:
-* using post-update methods like `update_layout`, `update_xaxes`, `update_traces`, or
-* by creating a custom `plotly.graph_objects.Figure()` object and manually adding traces with `add_trace`.
-
-For more details, refer to our [user guide on custom chart](custom-charts.md) and the
-[Plotly documentation on updating figures](https://plotly.com/python/creating-and-updating-figures/).
+- using post-update methods like `update_layout`, `update_xaxes`, `update_traces`, or
+- by creating a custom `plotly.graph_objects.Figure()` object and manually adding traces with `add_trace`.
+For more details, refer to our [user guide on custom chart](custom-charts.md) and the [Plotly documentation on updating figures](https://plotly.com/python/creating-and-updating-figures/).
## Add title, header, and footer
-The [`Graph`][vizro.models.Graph] accepts a `title`, `header` and `footer` argument. This is useful for providing
-context to the data being displayed, or for adding a description of the data.
+The [`Graph`][vizro.models.Graph] accepts a `title`, `header` and `footer` argument. This is useful for context on the data being displayed, or for adding a description of the data.
- **title**: Displayed as an [H3 header](https://dash.plotly.com/dash-html-components/h3), useful for summarizing the main topic or insight of the component.
- **header**: Accepts markdown text, ideal for extra descriptions, subtitles, or detailed data insights.
- **footer**: Accepts markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers.
-
!!! note
-
- Although you can directly provide a `title` to the Plotly Express chart, we recommend using `Graph.title` for
- proper alignment with other components on the screen.
+ Although you can directly give a `title` to the Plotly Express chart, we recommend using `Graph.title` for proper alignment with other components on the screen.
!!! example "Formatted Graph"
=== "app.py"
-
```{.python pycafe-link}
import vizro.models as vm
@@ -126,31 +111,34 @@ context to the data being displayed, or for adding a description of the data.
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: scatter
- x: sepal_width
- y: sepal_length
- color: species
- data_frame: iris
- title: Relationships between Sepal Width and Sepal Length
- header: |
- Each point in the scatter plot represents one of the 150 iris flowers, with colors indicating their
- types. The Setosa type is easily identifiable by its short and wide sepals.
-
- However, there is still overlap between the Versicolor and Virginica types when considering only sepal
- width and length.
- footer: |
- SOURCE: **Plotly iris data set, 2024**
- type: graph
- title: Formatted Graph
+ - components:
+ - figure:
+ _target_: scatter
+ x: sepal_width
+ y: sepal_length
+ color: species
+ data_frame: iris
+ title: Relationships between Sepal Width and Sepal Length
+ header: |
+ Each point in the scatter plot represents one of the 150 iris flowers, with colors indicating their
+ types. The Setosa type is easily identifiable by its short and wide sepals.
+
+ However, there is still overlap between the Versicolor and Virginica types when considering only sepal
+ width and length.
+ footer: |
+ SOURCE: **Plotly iris data set, 2024**
+ type: graph
+ title: Formatted Graph
```
+
=== "Result"
- [![FormattedGraph]][FormattedGraph]
+ [![FormattedGraph]][formattedgraph]
- [FormattedGraph]: ../../assets/user_guides/components/formatted_graph.png
+[formattedgraph]: ../../assets/user_guides/components/formatted_graph.png
+[graph]: ../../assets/user_guides/components/graph.png
diff --git a/vizro-core/docs/pages/user-guides/install.md b/vizro-core/docs/pages/user-guides/install.md
index 4d4c01239..6a07911e5 100644
--- a/vizro-core/docs/pages/user-guides/install.md
+++ b/vizro-core/docs/pages/user-guides/install.md
@@ -8,8 +8,8 @@ We recommend that you create a virtual environment for each Vizro project you wo
## Prerequisites to working locally
-* **Python**: Vizro supports macOS, Linux, and Windows. It works with Python 3.9 and later.
-* **Virtual environment**: You specify the version of Python to use with Vizro when you set up the virtual environment. See the following references to learn more about [Python virtual environments](https://realpython.com/python-virtual-environments-a-primer/), [Conda virtual environments](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html#starting-conda) or [watch an explainer video about them](https://youtu.be/YKfAwIItO7M).
+- **Python**: Vizro supports macOS, Linux, and Windows. It works with Python 3.9 and later.
+- **Virtual environment**: You specify the version of Python to use with Vizro when you set up the virtual environment. See the following references to learn more about [Python virtual environments](https://realpython.com/python-virtual-environments-a-primer/), [Conda virtual environments](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html#starting-conda) or [watch an explainer video about them](https://youtu.be/YKfAwIItO7M).
### How to create a virtual environment for your Vizro project
diff --git a/vizro-core/docs/pages/user-guides/kedro-data-catalog.md b/vizro-core/docs/pages/user-guides/kedro-data-catalog.md
index 0e2b0954e..ce4b060fa 100644
--- a/vizro-core/docs/pages/user-guides/kedro-data-catalog.md
+++ b/vizro-core/docs/pages/user-guides/kedro-data-catalog.md
@@ -3,6 +3,7 @@
This page describes how to integrate Vizro with [Kedro](https://docs.kedro.org/en/stable/index.html), an open-source Python framework to create reproducible, maintainable, and modular data science code. For Pandas datasets registered in a Kedro data catalog, Vizro provides a convenient way to visualize them.
## Installation
+
If you already have Kedro installed then you do not need to install any extra dependencies. If you do not have Kedro installed then you should run:
```bash
@@ -10,7 +11,9 @@ pip install vizro[kedro]
```
## Use datasets from the Kedro Data Catalog
+
`vizro.integrations.kedro` provides functions to help generate and process a [Kedro Data Catalog](https://docs.kedro.org/en/stable/data/index.html). Given a Kedro Data Catalog `catalog`, the general pattern to add datasets into the Vizro data manager is:
+
```python
from vizro.integrations import kedro as kedro_integration
from vizro.managers import data_manager
@@ -25,15 +28,14 @@ This imports all datasets of type [`kedro_datasets.pandas`](https://docs.kedro.o
The `catalog` variable may have been created in a number of different ways:
1. Kedro project path. Vizro exposes a helper function `vizro.integrations.kedro.catalog_from_project` to generate a `catalog` given the path to a Kedro project.
-2. [Kedro Jupyter session](https://docs.kedro.org/en/stable/notebooks_and_ipython/kedro_and_notebooks.html). This automatically exposes `catalog`.
-3. Data Catalog configuration file (`catalog.yaml`). This can create a `catalog` entirely independently of a Kedro project using [`kedro.io.DataCatalog.from_config`](https://docs.kedro.org/en/stable/kedro.io.DataCatalog.html#kedro.io.DataCatalog.from_config).
+1. [Kedro Jupyter session](https://docs.kedro.org/en/stable/notebooks_and_ipython/kedro_and_notebooks.html). This automatically exposes `catalog`.
+1. Data Catalog configuration file (`catalog.yaml`). This can create a `catalog` entirely independently of a Kedro project using [`kedro.io.DataCatalog.from_config`](https://docs.kedro.org/en/stable/kedro.io.DataCatalog.html#kedro.io.DataCatalog.from_config).
The full code for these different cases is given below.
!!! example "Import a Kedro Data Catalog into the Vizro data manager"
-
=== "app.py (Kedro project path)"
- ```py
+ ```python
from vizro.integrations import kedro as kedro_integration
from vizro.managers import data_manager
@@ -43,16 +45,18 @@ The full code for these different cases is given below.
for dataset_name, dataset in kedro_integration.datasets_from_catalog(catalog).items():
data_manager[dataset_name] = dataset
```
+
=== "app.ipynb (Kedro Jupyter session)"
- ```py
+ ```python
from vizro.managers import data_manager
for dataset_name, dataset in kedro_integration.datasets_from_catalog(catalog).items():
data_manager[dataset_name] = dataset
```
+
=== "app.py (Data Catalog configuration file)"
- ```py
+ ```python
from kedro.io import DataCatalog
import yaml
diff --git a/vizro-core/docs/pages/user-guides/layouts.md b/vizro-core/docs/pages/user-guides/layouts.md
index 8361560db..af66ec301 100644
--- a/vizro-core/docs/pages/user-guides/layouts.md
+++ b/vizro-core/docs/pages/user-guides/layouts.md
@@ -3,11 +3,10 @@
The [`Page`][vizro.models.Page] model accepts a `layout` argument that enables custom arrangement of charts and components on the screen. This guide shows how to customize the grid specifications in the [`Layout`][vizro.models.Layout].
## The default layout
-The `layout` argument of the [`Page`][vizro.models.Page] model is optional. If no layout is specified, all charts/components are automatically [**stacked vertically**](layouts.md#vertical-and-horizontal-stacking) on the page in one column.
-If you are happy with that arrangement, you can create your charts/components without providing a [`Layout`][vizro.models.Layout].
-!!! example "Default Layout"
+The `layout` argument of the [`Page`][vizro.models.Page] model is optional. If no layout is specified, all charts/components are automatically [**stacked vertically**](layouts.md#vertical-and-horizontal-stacking) on the page in one column. If you are happy with that arrangement, you can create your charts/components without providing a [`Layout`][vizro.models.Layout].
+!!! example "Default Layout"
=== "app.py"
```{.python pycafe-link}
from vizro import Vizro
@@ -23,35 +22,33 @@ If you are happy with that arrangement, you can create your charts/components wi
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- # Component 0
- type: card
- - text: |
- # Component 1
- type: card
- title: two_left
+ - components:
+ - text: |
+ # Component 0
+ type: card
+ - text: |
+ # Component 1
+ type: card
+ title: two_left
```
- === "Result"
- [![Layout]][Layout]
-
- [Layout]: ../../assets/user_guides/layout/two_left.png
-
+ === "Result"
+ [![Layout]][layout]
## Configure the grid
+
To customize the grid arrangement, configure the `grid` parameter of the [`Layout`][vizro.models.Layout] model.
The example below shows an example of a valid `grid`:
```python title="Basic example"
-grid = [[0, 1],
- [0, 2]]
+grid = [[0, 1], [0, 2]]
```
- The `grid` must be provided as `list[list[int]]` (for example, `grid = [[0, 1], [0, 2]]`).
@@ -64,16 +61,12 @@ grid = [[0, 1],
- The area spanned by a chart/component in the grid must be rectangular.
- The grid can be arbitrarily large, allowing arbitrarily granular control of the grid.
-
## Vertical and horizontal stacking
+
As described above, when no `Layout` is specified, components are presented **vertically** as a single-column stack. If you have three components, the default `Layout.grid` will be as follows, with three equally sized rows, each containing a component spanning the entire width:
```python title="Vertical stacking"
-grid = [
- [0],
- [1],
- [2]
- ]
+grid = [[0], [1], [2]]
```
To present components **horizontally** in one row:
@@ -89,8 +82,8 @@ This defines a single row that occupies the entire width and height, divided int
## Grid - basic example
-!!! example "Grid Arrangement - Basic Example"
+!!! example "Grid Arrangement - Basic Example"
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -109,39 +102,37 @@ This defines a single row that occupies the entire width and height, divided int
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- # Component 0
- type: card
- - text: |
- # Component 1
- type: card
- - text: |
- # Component 2
- type: card
- layout:
- grid: [[0, 1], [0, 2]]
- title: one_left_two_right
+ - components:
+ - text: |
+ # Component 0
+ type: card
+ - text: |
+ # Component 1
+ type: card
+ - text: |
+ # Component 2
+ type: card
+ layout:
+ grid: [[0, 1], [0, 2]]
+ title: one_left_two_right
```
- === "Result"
- [![Grid]][Grid]
- [Grid]: ../../assets/user_guides/layout/one_left_two_right.png
+ === "Result"
+ [![Grid]][grid]
## Grid - advanced example
If you want to divide the grid into subgrids with finer control over these, you can use [`Containers`](container.md). See our section on [when to use `Containers` vs. `Page.layout`](container.md#when-to-use-containers) for more information.
-The `Layout` provides full control over the arrangement of top-level components within a page,
-allowing arbitrarily granular control of the grid by creating larger grids.
+The `Layout` provides full control over the arrangement of top-level components within a page, allowing arbitrarily granular control of the grid by creating larger grids.
!!! example "Grid Arrangement - Advanced Example"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -208,6 +199,7 @@ allowing arbitrarily granular control of the grid by creating larger grids.
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -260,44 +252,44 @@ allowing arbitrarily granular control of the grid by creating larger grids.
grid: [[0, 1, 3, 4], [2, 2, 3, 4]]
title: Custom Layout - Advanced Example
```
- === "Result"
- [![GridAdv]][GridAdv]
- [GridAdv]: ../../assets/user_guides/layout/grid_advanced.png
+ === "Result"
+ [![GridAdv]][gridadv]
## Custom layout examples
+
Here is a reference table of example layouts:
+
one row with one component, second row with two components stacked horizontally
-| Layout needed | Grid | Code |
-|--------------------------------|----------------------------|-------------------------------------------------------------------------------------|
-| | | `layout=vm.Layout(grid=[[0]])` |
-| | | `layout=vm.Layout(grid=[[0],[1]])` |
-| | | `layout=vm.Layout(grid=[[0,1]])` |
-| | | `layout=vm.Layout(grid=[[0],[1],[2]])` or `layout=None` |
-| | | `layout=vm.Layout(grid=[[0,1],[0,2]])` |
-| | | `layout=vm.Layout(grid=[[0,0],[1,2]])` |
-| | | `layout=vm.Layout(grid=[[0,1],[2,2]])` |
-| | | `layout=vm.Layout(grid=[[0,1],[0,2],[0,3]])` |
-| | | `layout=vm.Layout(grid=[[0,1],[2,3]])` |
-| | | `layout=vm.Layout(grid=[[0,3],[1,3],[2,3]])` |
-| | | `layout=vm.Layout(grid=[[0,0,0],[1,2,3]])` |
-| | | `layout=vm.Layout(grid=[[0,1,2],[3,3,3]])` |
+| Layout needed | Grid | Code |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
+| | | `layout=vm.Layout(grid=[[0]])` |
+| | | `layout=vm.Layout(grid=[[0],[1]])` |
+| | | `layout=vm.Layout(grid=[[0,1]])` |
+| | | `layout=vm.Layout(grid=[[0],[1],[2]])` or `layout=None` |
+| | | `layout=vm.Layout(grid=[[0,1],[0,2]])` |
+| | | `layout=vm.Layout(grid=[[0,0],[1,2]])` |
+| | | `layout=vm.Layout(grid=[[0,1],[2,2]])` |
+| | | `layout=vm.Layout(grid=[[0,1],[0,2],[0,3]])` |
+| | | `layout=vm.Layout(grid=[[0,1],[2,3]])` |
+| | | `layout=vm.Layout(grid=[[0,3],[1,3],[2,3]])` |
+| | | `layout=vm.Layout(grid=[[0,0,0],[1,2,3]])` |
+| | | `layout=vm.Layout(grid=[[0,1,2],[3,3,3]])` |
## Add empty sections to the grid
+
One approach to organize the dashboard's layout involves integrating empty sections by specifying `-1` within the grid layout.
```python title="Example"
-grid = [[0, 1, -1],
- [0, 2, -1]]
+grid = [[0, 1, -1], [0, 2, -1]]
```
!!! example "Adding Empty Spaces"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -316,38 +308,38 @@ grid = [[0, 1, -1],
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- # Component 0
- type: card
- - text: |
- # Component 1
- type: card
- - text: |
- # Component 2
- type: card
- layout:
- grid: [[0, 1, -1], [0, 2, -1]]
- title: Adding empty spaces
+ - components:
+ - text: |
+ # Component 0
+ type: card
+ - text: |
+ # Component 1
+ type: card
+ - text: |
+ # Component 2
+ type: card
+ layout:
+ grid: [[0, 1, -1], [0, 2, -1]]
+ title: Adding empty spaces
```
- === "Result"
- [![GridEmpty]][GridEmpty]
- [GridEmpty]: ../../assets/user_guides/layout/layout_empty_spaces.png
+ === "Result"
+ [![GridEmpty]][gridempty]
## Control the scroll behavior
+
By default, the grid fits all charts/components on the screen. This can lead to distortions such that the chart/component looks squashed. To control the scroll behavior, you can specify the following:
- `row_min_height`: Sets a chart/component's minimum height. Defaults to 0px.
- `col_min_width`: Sets a chart/component's minimum width. Defaults to 0px.
!!! example "Activate Scrolling"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -371,59 +363,63 @@ By default, the grid fits all charts/components on the screen. This can lead to
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- # Component 0
- type: card
- - text: |
- # Component 1
- type: card
- - text: |
- # Component 2
- type: card
- - text: |
- # Component 2
- type: card
- - text: |
- # Component 4
- type: card
- - text: |
- # Component 5
- type: card
- - text: |
- # Component 6
- type: card
- - text: |
- # Component 7
- type: card
- layout:
- grid: [[0], [1], [2], [3], [4], [5], [6], [7]]
- row_min_height: 240px
- title: Activate scrolling
+ - components:
+ - text: |
+ # Component 0
+ type: card
+ - text: |
+ # Component 1
+ type: card
+ - text: |
+ # Component 2
+ type: card
+ - text: |
+ # Component 2
+ type: card
+ - text: |
+ # Component 4
+ type: card
+ - text: |
+ # Component 5
+ type: card
+ - text: |
+ # Component 6
+ type: card
+ - text: |
+ # Component 7
+ type: card
+ layout:
+ grid: [[0], [1], [2], [3], [4], [5], [6], [7]]
+ row_min_height: 240px
+ title: Activate scrolling
```
- === "Result"
- [![GridScroll]][GridScroll]
-
- [GridScroll]: ../../assets/user_guides/layout/grid_scroll.png
+ === "Result"
+ [![GridScroll]][gridscroll]
## Further customization
-For further customization, such as changing the gap between row and column, refer to the
-documentation of the [`Layout`][vizro.models.Layout] model.
+
+For further customization, such as changing the gap between row and column, refer to the documentation of the [`Layout`][vizro.models.Layout] model.
## Alternative layout approaches
+
In general, any arbitrarily granular layout can already be achieved using [`Page.layout`](layouts.md) alone and is our recommended approach if you want to arrange components on a page with consistent row and/or column spacing.
!!! note "Alternative layout approaches: `Tabs` and `Containers`"
-
- [`Tabs`][vizro.models.Tabs] and [`Containers`][vizro.models.Container] provide an alternative approach to customize your page layout.
- For example, if you want to have more granular control and break the overall page grid into subgrids, see our [user guide on Containers](container.md).
+ [`Tabs`][vizro.models.Tabs] and [`Containers`][vizro.models.Container] offer an alternative approach to customize your page layout. For example, if you want to have more granular control and break the overall page grid into subgrids, see our [user guide on Containers](container.md).
If you want to display multiple containers on one page by putting them into the same screen space, and letting the user switch between them, see our [user guide on Tabs](tabs.md).
![tabs](../../assets/user_guides/components/tabs-info.png){ width="500" }
+
+[grid]: ../../assets/user_guides/layout/one_left_two_right.png
+[gridadv]: ../../assets/user_guides/layout/grid_advanced.png
+[gridempty]: ../../assets/user_guides/layout/layout_empty_spaces.png
+[gridscroll]: ../../assets/user_guides/layout/grid_scroll.png
+[layout]: ../../assets/user_guides/layout/two_left.png
diff --git a/vizro-core/docs/pages/user-guides/navigation.md b/vizro-core/docs/pages/user-guides/navigation.md
index 41c6bb9dc..75a661470 100644
--- a/vizro-core/docs/pages/user-guides/navigation.md
+++ b/vizro-core/docs/pages/user-guides/navigation.md
@@ -2,8 +2,7 @@
This guide shows you how to use and customize the navigation that appears on the left of your dashboard.
-The [`Dashboard`][vizro.models.Dashboard] model accepts a `navigation` argument, where you can enter a [`Navigation`][vizro.models.Navigation] model. This enables you to group pages together and customize how they appear in your navigation.
-The dashboard includes a collapsible side panel that users can minimize or expand by a button click. The collapse button, located in the top right corner of the side panel, is visible by default for user convenience.
+The [`Dashboard`][vizro.models.Dashboard] model accepts a `navigation` argument, where you can enter a [`Navigation`][vizro.models.Navigation] model. This enables you to group pages together and customize how they appear in your navigation. The dashboard includes a collapsible side panel that users can minimize or expand by a button click. The collapse button, located in the top right corner of the side panel, is visible by default for user convenience.
## Use the default navigation
@@ -56,8 +55,8 @@ By default, if the `navigation` argument is not specified, Vizro creates a navig
type: graph
title: My first page
- components:
- - text: My text here
- type: card
+ - text: My text here
+ type: card
title: My second page
- components:
- figure:
@@ -69,10 +68,9 @@ By default, if the `navigation` argument is not specified, Vizro creates a navig
type: graph
title: My third page
```
- === "Result"
- [![DefaultNavigation]][DefaultNavigation]
- [DefaultNavigation]: ../../assets/user_guides/navigation/default_navigation.png
+ === "Result"
+ [![DefaultNavigation]][defaultnavigation]
## Include a subset of pages
@@ -132,17 +130,15 @@ To include only some of your dashboard pages in your navigation then list them i
- My first page
- My second page
```
- === "Result"
- [![OnlySomePages]][OnlySomePages]
- [OnlySomePages]: ../../assets/user_guides/navigation/only_some_pages.png
+ === "Result"
+ [![OnlySomePages]][onlysomepages]
## Group pages
You can also group your pages together by specifying `pages` as a dictionary:
!!! example "Grouping pages"
-
=== "snippet.py"
```py
# page_1, page_2, page_3 defined as in default example
@@ -154,7 +150,6 @@ You can also group your pages together by specifying `pages` as a dictionary:
```
=== "app.py"
-
```{.python pycafe-link}
from vizro import Vizro
import vizro.plotly.express as px
@@ -187,6 +182,7 @@ You can also group your pages together by specifying `pages` as a dictionary:
)
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -200,18 +196,15 @@ You can also group your pages together by specifying `pages` as a dictionary:
Group B:
- My third page
```
- === "Result"
- [![GroupedNavigation]][GroupedNavigation]
-
- [GroupedNavigation]: ../../assets/user_guides/navigation/grouped_navigation.png
+ === "Result"
+ [![GroupedNavigation]][groupednavigation]
## Use a navigation bar with icons
Another way to group together pages in the navigation is to use a [`NavBar`][vizro.models.NavBar] with icons. The simplest way to use this is to change the `nav_selector` specified in [`Navigation`][vizro.models.Navigation]:
!!! example "Using `NavBar`"
-
=== "snippet.py"
```py
# page_1, page_2, page_3 defined as in default example
@@ -223,8 +216,8 @@ Another way to group together pages in the navigation is to use a [`NavBar`][viz
)
Vizro().build(dashboard).run()
```
- === "app.py"
+ === "app.py"
```{.python pycafe-link}
from vizro import Vizro
import vizro.plotly.express as px
@@ -276,14 +269,11 @@ Another way to group together pages in the navigation is to use a [`NavBar`][viz
nav_selector:
type: nav_bar
```
- === "Result"
- [![NavBar]][NavBar]
-
- [NavBar]: ../../assets/user_guides/navigation/nav_bar.png
+ === "Result"
+ [![NavBar]][navbar]
-Here, the first level of the navigation hierarchy ("Group A" and "Group B") is represented by an icon in a navigation bar, and the second level of the navigation (the pages) is represented by an accordion.
-By default, the set of icons used are the [`filter` icons from the Google Material icons library](https://fonts.google.com/icons?icon.query=filter). The icon label ("Group A" and "Group B") appears as a tooltip on hovering over the icon.
+Here, the first level of the navigation hierarchy ("Group A" and "Group B") is represented by an icon in a navigation bar, and the second level of the navigation (the pages) is represented by an accordion. By default, the set of icons used are the [`filter` icons from the Google Material icons library](https://fonts.google.com/icons?icon.query=filter). The icon label ("Group A" and "Group B") appears as a tooltip on hovering over the icon.
## Customize the navigation bar
@@ -314,7 +304,6 @@ The same configuration for [grouping pages](#group-pages) applies inside a `NavL
```
=== "app.py"
-
```{.python pycafe-link}
from vizro import Vizro
import vizro.plotly.express as px
@@ -375,10 +364,9 @@ The same configuration for [grouping pages](#group-pages) applies inside a `NavL
Group B:
- My third page
```
- === "Result"
- [![AccordionInsideNavBar]][AccordionInsideNavBar]
- [AccordionInsideNavBar]: ../../assets/user_guides/navigation/accordion_inside_nav_bar.png
+ === "Result"
+ [![AccordionInsideNavBar]][accordioninsidenavbar]
You can alter the icons used by specifying the name of the icon in the [Google Material icons library](https://fonts.google.com/icons):
@@ -402,8 +390,8 @@ You can alter the icons used by specifying the name of the icon in the [Google M
),
)
```
- === "app.py"
+ === "app.py"
```{.python pycafe-link}
from vizro import Vizro
import vizro.plotly.express as px
@@ -468,7 +456,13 @@ You can alter the icons used by specifying the name of the icon in the [Google M
pages:
- My third page
```
- === "Result"
- [![CustomIcons]][CustomIcons]
- [CustomIcons]: ../../assets/user_guides/navigation/custom_icons.png
+ === "Result"
+ [![CustomIcons]][customicons]
+
+[accordioninsidenavbar]: ../../assets/user_guides/navigation/accordion_inside_nav_bar.png
+[customicons]: ../../assets/user_guides/navigation/custom_icons.png
+[defaultnavigation]: ../../assets/user_guides/navigation/default_navigation.png
+[groupednavigation]: ../../assets/user_guides/navigation/grouped_navigation.png
+[navbar]: ../../assets/user_guides/navigation/nav_bar.png
+[onlysomepages]: ../../assets/user_guides/navigation/only_some_pages.png
diff --git a/vizro-core/docs/pages/user-guides/pages.md b/vizro-core/docs/pages/user-guides/pages.md
index 7ae944e9b..71e01e9f9 100644
--- a/vizro-core/docs/pages/user-guides/pages.md
+++ b/vizro-core/docs/pages/user-guides/pages.md
@@ -1,7 +1,6 @@
# How to use pages
-This guide shows you how to add pages to your dashboard and customize the URL paths if needed.
-A [`Page`][vizro.models.Page] lets you place and arrange your dashboard content (for example, chart/components, tables, and text)
-and configure your dashboard interactions (such as filters and parameters).
+
+This guide shows you how to add pages to your dashboard and customize the URL paths if needed. A [`Page`][vizro.models.Page] lets you place and arrange your dashboard content (for example, chart/components, tables, and text) and configure your dashboard interactions (such as filters and parameters).
The [`Dashboard`][vizro.models.Dashboard] model accepts the `pages` argument, where you can insert your [`Page`][vizro.models.Page].
@@ -10,19 +9,19 @@ The [`Dashboard`][vizro.models.Dashboard] model accepts the `pages` argument, wh
A [`Page`][vizro.models.Page] is split up into four main containers:
1. The **navigation container** where you can customize your `navigation` (see [Dashboard](dashboard.md) and [Navigation](navigation.md) for more information). Note that the navigation container needs to be configured via the Dashboard.
-2. The **control container** where you can add your `controls` (see [Filters](filters.md) or [Parameters](parameters.md)) to interact with the dashboard
-3. The **page header** that contains the page title and the theme toggle switch button
-4. The **component container** where you can add your [components](components.md) to visualize your data
+1. The **control container** where you can add your `controls` (see [Filters](filters.md) or [Parameters](parameters.md)) to interact with the dashboard
+1. The **page header** that contains the page title and the theme toggle switch button
+1. The **component container** where you can add your [components](components.md) to visualize your data
![Page Container](../../assets/user_guides/pages/page_containers.png)
To create and add a page to your dashboard, do the following steps:
1. Set a `title` for your [`Page`][vizro.models.Page]
-2. Configure your `components`, see our guide on the [various options](components.md)
-3. (optional) Configure your `controls` , see our guides on [Filters](filters.md) and [Parameters](parameters.md)
-4. (optional) Configure your `layout` , see our guide on [Layouts](layouts.md)
-5. (optional) Give a `description` of your `Page` to the app's [meta tags](https://metatags.io/)
+1. Configure your `components`, see our guide on the [various options](components.md)
+1. (optional) Configure your `controls` , see our guides on [Filters](filters.md) and [Parameters](parameters.md)
+1. (optional) Configure your `layout` , see our guide on [Layouts](layouts.md)
+1. (optional) Give a `description` of your `Page` to the app's [meta tags](https://metatags.io/)
!!! example "Page"
=== "app.py"
@@ -51,51 +50,47 @@ To create and add a page to your dashboard, do the following steps:
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: sunburst
- path: ['continent', 'country']
- values: pop
- color: lifeExp
- data_frame: gapminder
- id: sunburst
- type: graph
- controls:
- - column: continent
- targets:
- - sunburst
- type: filter
- - selector:
- options: ['lifeExp', 'pop']
- title: Color
- type: radio_items
- targets:
- - sunburst.color
- type: parameter
- title: Page Title
- description: "Longer description of the page content"
+ - components:
+ - figure:
+ _target_: sunburst
+ path: [continent, country]
+ values: pop
+ color: lifeExp
+ data_frame: gapminder
+ id: sunburst
+ type: graph
+ controls:
+ - column: continent
+ targets: [sunburst]
+ type: filter
+ - selector:
+ options: [lifeExp, pop]
+ title: Color
+ type: radio_items
+ targets: [sunburst.color]
+ type: parameter
+ title: Page Title
+ description: Longer description of the page content
```
- === "Result"
- [![Page]][Page]
- [Page]: ../../assets/user_guides/pages/page_sunburst.png
+ === "Result"
+ [![Page]][page]
An accordion page selector is automatically added to your dashboard in the top-left of the control container for through the different pages. It will not be added if your dashboard consists of only one page.
You can additionally navigate through the different pages by going directly to the relevant page URL (more details in next section).
-
## Customize the page URL
-By default, the page URL is automatically generated based on the `id` of the page. For example, if `id="This is my first page"`
-the generated page URL will be `path=this-is-my-first-page`. You can then access the page via `localhost:/this-is-my-first-page`.
-Note that the page `id` defaults to be the same as the page `title` if not set.
-If you have multiple pages with the same `title` then you must assign a unique `id`.
+By default, the page URL is automatically generated based on the `id` of the page. For example, if `id="This is my first page"` the generated page URL will be `path=this-is-my-first-page`. You can then access the page via `localhost:/this-is-my-first-page`.
+
+Note that the page `id` defaults to be the same as the page `title` if not set. If you have multiple pages with the same `title` then you must assign a unique `id`.
The first page always has the URL prefix `/` assigned. A custom URL can, therefore, not be created for the first page.
@@ -137,39 +132,40 @@ To customize the page URL, pass a valid URL name to the `path` argument of [`Pag
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - text: |
- Commodi repudiandae consequuntur voluptatum.
- type: card
- title: Page 1
- - components:
- - figure:
- _target_: sunburst
- path: ['continent', 'country']
- values: pop
- color: lifeExp
- data_frame: gapminder
- id: sunburst
- type: graph
- controls:
- - column: continent
- targets:
- - sunburst
- type: filter
- - selector:
- options: ['lifeExp', 'pop']
- title: Color
- type: radio_items
- targets:
- - sunburst.color
- type: parameter
- title: Page 2
- path: my-custom-url
+ - components:
+ - text: |
+ Commodi repudiandae consequuntur voluptatum.
+ type: card
+ title: Page 1
+ - components:
+ - figure:
+ _target_: sunburst
+ path: [continent, country]
+ values: pop
+ color: lifeExp
+ data_frame: gapminder
+ id: sunburst
+ type: graph
+ controls:
+ - column: continent
+ targets: [sunburst]
+ type: filter
+ - selector:
+ options: [lifeExp, pop]
+ title: Color
+ type: radio_items
+ targets: [sunburst.color]
+ type: parameter
+ title: Page 2
+ path: my-custom-url
```
You can now access the first page via `localhost:/` and the second page via `localhost:/my-custom-url`.
+
+[page]: ../../assets/user_guides/pages/page_sunburst.png
diff --git a/vizro-core/docs/pages/user-guides/parameters.md b/vizro-core/docs/pages/user-guides/parameters.md
index bb39a7a0c..c82707d4a 100644
--- a/vizro-core/docs/pages/user-guides/parameters.md
+++ b/vizro-core/docs/pages/user-guides/parameters.md
@@ -9,8 +9,8 @@ The [`Page`][vizro.models.Page] model accepts the `controls` argument, where you
To add a parameter to your page, do the following:
1. add the [`Parameter`][vizro.models.Parameter] model into the `controls` argument of the [`Page`][vizro.models.Page] model.
-2. add the `targets` argument
-3. add a selector model to the `selector` argument.
+1. add the `targets` argument
+1. add a selector model to the `selector` argument.
In the `targets` argument, you can specify the component and function argument that the parameter should be applied to in the form of `.` (for example, `scatter_chart.title`).
@@ -48,6 +48,7 @@ Unlike for the [`Filter`][vizro.models.Filter] model, you also have to configure
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -64,18 +65,17 @@ Unlike for the [`Filter`][vizro.models.Filter] model, you also have to configure
type: graph
controls:
- selector:
- options: ["My scatter chart", "A better title!", "Another title..."]
- multi: False
+ options: [My scatter chart, A better title!, Another title...]
+ multi: false
type: dropdown
targets:
- scatter_chart.title
type: parameter
title: My first page
```
- === "Result"
- [![Parameter]][Parameter]
- [Parameter]: ../../assets/user_guides/control/control4.png
+ === "Result"
+ [![Parameter]][parameter]
If you would like to pass `None` as a parameter and make a parameter optional, you can specify the string `"NONE"` in the `options` or `value` field.
@@ -133,6 +133,7 @@ If you want to change nested parameters, you can specify the `targets` argument
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -146,7 +147,7 @@ If you want to change nested parameters, you can specify the `targets` argument
y: sepal_length
size: petal_length
color: species
- color_discrete_map: {"setosa": "#00b4ff", "versicolor": "#ff9222"}
+ color_discrete_map: {setosa: '#00b4ff', versicolor: '#ff9222'}
id: scatter_chart
type: graph
- figure:
@@ -155,23 +156,22 @@ If you want to change nested parameters, you can specify the `targets` argument
x: sepal_width
y: sepal_length
color: species
- color_discrete_map: {"setosa": "#00b4ff", "versicolor": "#ff9222"}
+ color_discrete_map: {setosa: '#00b4ff', versicolor: '#ff9222'}
id: bar_chart
type: graph
controls:
- selector:
- options: ["#ff5267", "#3949ab"]
+ options: ['#ff5267', '#3949ab']
value: #3949ab
- multi: False
+ multi: false
type: dropdown
- targets: ["scatter_chart.color_discrete_map.virginica", "bar_chart.color_discrete_map.virginica"]
+ targets: [scatter_chart.color_discrete_map.virginica, bar_chart.color_discrete_map.virginica]
type: parameter
title: My first page
```
- === "Result"
- [![Nested]][Nested]
- [Nested]: ../../assets/user_guides/control/control5.png
+ === "Result"
+ [![Nested]][nested]
In the above example, the object passed to the function argument `color_discrete_map` is a dictionary which maps the different flower species to fixed colors (for example, `{"virginica":"blue"}`). In this case, only the value `blue` should be changed instead of the entire dictionary. This can be achieved by specifying a target as `scatter.color_discrete_map.virginica`.
@@ -180,3 +180,6 @@ Note that in the above example, one parameter affects multiple targets.
## Dynamic data parameters
If you use [dynamic data](data.md/#dynamic-data) that can be updated while the dashboard is running then you can pass parameters to the dynamic data function to alter the data loaded into your dashboard. For detailed instructions, refer to the section on [parametrized data loading](data.md/#parametrize-data-loading).
+
+[nested]: ../../assets/user_guides/control/control5.png
+[parameter]: ../../assets/user_guides/control/control4.png
diff --git a/vizro-core/docs/pages/user-guides/run.md b/vizro-core/docs/pages/user-guides/run.md
index 29ada2935..028eb5027 100644
--- a/vizro-core/docs/pages/user-guides/run.md
+++ b/vizro-core/docs/pages/user-guides/run.md
@@ -15,7 +15,6 @@ Most of our examples have a link below the code, [Run and edit this code in PyCa
You can use [PyCafe](https://py.cafe/snippet/vizro/v1) snippet mode to experiment with your own Vizro dashboards by dropping code into a new project.
-
## Default built-in Flask development server
!!! example "Default built-in Flask development server"
@@ -38,9 +37,10 @@ You can use [PyCafe](https://py.cafe/snippet/vizro/v1) snippet mode to experimen
Vizro().build(dashboard).run()
```
+
1. create a Python file named `app.py`.
-2. type the command `python app.py` into your terminal.
-3. information below will be displayed in your terminal, go to [http://127.0.0.1:8050/](http://127.0.0.1:8050/).
+1. type the command `python app.py` into your terminal.
+1. information below will be displayed in your terminal, go to [http://127.0.0.1:8050/](http://127.0.0.1:8050/).
```
Dash is running on http://127.0.0.1:8050/
@@ -51,8 +51,7 @@ INFO:werkzeug:WARNING: This is a development server. Do not use it in a producti
```
!!! warning "In production"
-
- As per the above warning message, which is [further explained in the Flask documentation](https://flask.palletsprojects.com/en/3.0.x/deploying/), the Flask development server is intended for use only during local development and **should not** be used when deploying to production. Instead, you should instead use a production-ready solution such as [Gunicorn](#gunicorn).
+ The above warning message is [further explained in the Flask documentation](https://flask.palletsprojects.com/en/3.0.x/deploying/). The Flask development server is intended for use only during local development and **should not** be used when deploying to production. Instead, you should instead use a production-ready solution such as [Gunicorn](#gunicorn).
### Automatic reloading and debugging
@@ -64,11 +63,11 @@ Setting `debug=True` enables [Dash Dev Tools](https://dash.plotly.com/devtools).
In addition, some errors generated at run time can also be viewed via the browser console (for example in `Chrome` see `View > Developer > Developer Tools > Console`).
-
## Jupyter
+
The dashboard application can be launched in a Jupyter environment in `inline`, `external`, and `jupyterlab` mode.
-!!! example "Run in a Jupyter Notebook in inline mode"
+!!! example "Run in a Jupyter Notebook in inline mode"
=== "app.ipynb"
```py linenums="1"
from vizro import Vizro
@@ -80,23 +79,23 @@ The dashboard application can be launched in a Jupyter environment in `inline`,
page = vm.Page(
title="My first page",
components=[
- vm.Graph(id="scatter_chart", figure=px.scatter(iris, x="sepal_length", y="petal_width", color="species")),
+ vm.Graph(figure=px.scatter(iris, x="sepal_length", y="petal_width", color="species")),
],
)
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run(jupyter_mode="external")
```
+
- by default, the mode is set to `inline` in `run()` and the dashboard will be displayed inside your Jupyter environment.
- you can specify `jupyter_mode="external"` and a link will be displayed to direct you to the localhost where the dashboard is running.
- you can use tab mode by `jupyter_mode="tab"` to automatically open the app in a new browser
!!! note "Reloading and debugging"
-
Code reloading and hot reloading do not work within a Jupyter Notebook. Instead, there are two methods to reload the dashboard:
- * Restart the Jupyter kernel and re-run your notebook.
- * Add a cell containing `from vizro import Vizro; Vizro._reset()` to the top of your notebook and re-run it. With this method, there is no need to restart the Jupyter kernel.
+ - Restart the Jupyter kernel and re-run your notebook.
+ - Add a cell containing `from vizro import Vizro; Vizro._reset()` to the top of your notebook and re-run it. With this method, there is no need to restart the Jupyter kernel.
## Gunicorn
@@ -114,7 +113,7 @@ The dashboard application can be launched in a Jupyter environment in `inline`,
page = vm.Page(
title="My first page",
components=[
- vm.Graph(id="scatter_chart", figure=px.scatter(iris, x="sepal_length", y="petal_width", color="species")),
+ vm.Graph(figure=px.scatter(iris, x="sepal_length", y="petal_width", color="species")),
],
)
@@ -126,17 +125,18 @@ The dashboard application can be launched in a Jupyter environment in `inline`,
```
1. The Vizro `app` object is a WSGI application that exposes the underlying Flask app; this will be used by Gunicorn.
- 2. Enable the same app to still be run using the built-in Flask server with `python app.py` for development purposes.
+ 1. Enable the same app to still be run using the built-in Flask server with `python app.py` for development purposes.
To run using Gunicorn with four worker processes, execute
+
```bash
gunicorn app:app --workers 4
```
+
in the command line. For more Gunicorn configuration options, refer to [Gunicorn documentation](https://docs.gunicorn.org/).
!!! warning "In production"
-
- If your dashboard uses [dynamic data](data.md#dynamic-data) that can be refreshed while the dashboard is running then you should [configure your data manager cache](data.md#configure-cache) to use a backend that supports multiple processes.
+ If your dashboard uses [dynamic data](data.md#dynamic-data) that can be refreshed while the dashboard is running then you should [configure your data manager cache](data.md#configure-cache) to use a back end that supports multiple processes.
## Deployment
@@ -149,6 +149,6 @@ Internally, `app = Vizro()` contains a Flask app in `app.dash.server`. However,
[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This enables you to configure the underlying Dash app using the same [arguments that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, these arguments may be useful:
-- `url_base_pathname`: serve your Vizro app at a specific path rather than at the domain root. For example, if you host your dashboard at http://www.example.com/my_dashboard/ then you would set `url_base_pathname="/my_dashboard/"` or an environment variable `DASH_URL_BASE_PATHNAME="/my_dashboard/"`.
+- `url_base_pathname`: serve your Vizro app at a specific path rather than at the domain root. For example, if you host your dashboard at `http://www.example.com/my_dashboard/` then you would set `url_base_pathname="/my_dashboard/"` or an environment variable `DASH_URL_BASE_PATHNAME="/my_dashboard/"`.
- `serve_locally`: set to `False` to [serve Dash component libraries from a Content Delivery Network (CDN)](https://dash.plotly.com/external-resources#serving-dash's-component-libraries-locally-or-from-a-cdn), which reduces load on the server and can improve performance. Vizro uses [jsDeliver](https://www.jsdelivr.com/) as a CDN for CSS and JavaScript sources.
- `assets_external_path`: when `serve_locally=False`, you can also set `assets_external_path` or an environment variable `DASH_ASSETS_EXTERNAL_PATH` to [serve your own assets from a CDN](https://dash.plotly.com/external-resources#load-assets-from-a-folder-hosted-on-a-cdn).
diff --git a/vizro-core/docs/pages/user-guides/selectors.md b/vizro-core/docs/pages/user-guides/selectors.md
index 944515ab6..a1bd4be20 100644
--- a/vizro-core/docs/pages/user-guides/selectors.md
+++ b/vizro-core/docs/pages/user-guides/selectors.md
@@ -6,10 +6,7 @@ The [`Filter`][vizro.models.Filter] or the [`Parameter`][vizro.models.Parameter]
## Categorical selectors
-Within the categorical selectors, a clear distinction exists between multi-option and single-option selectors.
-For instance, the [`Checklist`][vizro.models.Checklist] functions as a multi-option selector by default while
-the [`RadioItem`][vizro.models.RadioItems] serves as a single-option selector by default. However, the
-[`Dropdown`][vizro.models.Dropdown] can function as both a multi-option or single-option selector.
+Within the categorical selectors, a clear distinction exists between multi-option and single-option selectors. For instance, the [`Checklist`][vizro.models.Checklist] functions as a multi-option selector by default while the [`RadioItem`][vizro.models.RadioItems] serves as a single-option selector by default. However, the [`Dropdown`][vizro.models.Dropdown] can function as both a multi-option or single-option selector.
For more information, refer to the API reference of the selector, or the documentation of its underlying Dash component:
@@ -18,15 +15,12 @@ For more information, refer to the API reference of the selector, or the documen
- [`RadioItems`][vizro.models.RadioItems] based on [`dcc.RadioItems`](https://dash.plotly.com/dash-core-components/radioitems)
!!! note
-
- When configuring the `options` of the categorical selectors, you can either provide:
+ When configuring the `options` of the categorical selectors, you can either give:
- a list of values `options = ['Value A', 'Value B', 'Value C']`
- or a dictionary of label-value mappings `options=[{'label': 'True', 'value': True}, {'label': 'False', 'value': False}]`
- The later is required if you want to provide different display labels to your option values or in case you want to
- provide boolean values as options. In this case, you need to provide a string label for your boolean values as
- boolean values cannot be displayed properly as labels in the underlying Dash components.
+ The later is required if you want to provide different display labels to your option values or in case you want to provide boolean values as options. In this case, you need to provide a string label for your boolean values as boolean values cannot be displayed properly as labels in the underlying Dash components.
## Numerical selectors
@@ -36,11 +30,7 @@ For more information, refer to the API reference of the selector, or the documen
- [`RangeSlider`][vizro.models.RangeSlider] based on [`dcc.RangeSlider`](https://dash.plotly.com/dash-core-components/rangeslider)
!!! note
-
- When configuring the [`Slider`][vizro.models.Slider] and the [`RangeSlider`][vizro.models.RangeSlider] with float values, and using `step` with an integer value, you may notice
- unexpected behavior, such as the drag value being outside its indicated marks.
- To our knowledge, this is a current bug in the underlying [`dcc.Slider`](https://dash.plotly.com/dash-core-components/slider) and
- [`dcc.RangeSlider`](https://dash.plotly.com/dash-core-components/rangeslider) component, which you can circumvent by adapting the `step` size accordingly.
+ When configuring the [`Slider`][vizro.models.Slider] and the [`RangeSlider`][vizro.models.RangeSlider] with float values, and using `step` with an integer value, you may notice unexpected behavior, such as the drag value being outside its indicated marks. To our knowledge, this is a current bug in the underlying [`dcc.Slider`](https://dash.plotly.com/dash-core-components/slider) and [`dcc.RangeSlider`](https://dash.plotly.com/dash-core-components/rangeslider) component, which you can circumvent by adapting the `step` size as needed.
## Temporal selectors
@@ -49,96 +39,6 @@ For more information, refer to the API reference of the selector, or the documen
- [`DatePicker`][vizro.models.DatePicker] based on [`dmc.DateRangePicker`](https://www.dash-mantine-components.com/components/datepicker#daterangepicker) and [`dmc.DatePicker`](https://www.dash-mantine-components.com/components/datepicker)
!!! note
-
When the [`DatePicker`][vizro.models.DatePicker] is configured with `range=True` (the default), the underlying component is `dmc.DateRangePicker`. When `range=False` the underlying component is `dmc.DatePicker`.
When configuring the [`DatePicker`][vizro.models.DatePicker] make sure to provide your dates for `min`, `max` and `value` arguments in `"yyyy-mm-dd"` format or as `datetime` type (for example, `datetime.datetime(2024, 01, 01)`).
-
-## Default selectors
-
-If you don't specify a selector, a default selector is applied based on the data type of the provided column.
-
-Default selectors for:
-
- - categorical data: [`Dropdown`][vizro.models.Dropdown]
- - numerical data: [`RangeSlider`][vizro.models.RangeSlider]
- - temporal data: [`DatePicker(range=True)`][vizro.models.DatePicker]
-
-Categorical selectors can be used independently of the data type of the column being filtered.
-
-To use numerical [`Filter`][vizro.models.Filter] selectors, the filtered column must be of `numeric` format,
-indicating that [pandas.api.types.is_numeric_dtype()](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_numeric_dtype.html) must return `True` for the filtered column.
-
-To use temporal [`Filter`][vizro.models.Filter] selectors, the filtered column must be of `datetime` format,
-indicating that [pandas.api.types.is_datetime64_any_dtype()](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_datetime64_any_dtype.html) must return `True` for the filtered column.
-
-`pd.DataFrame` column types can be changed to `datetime` using [pandas.to_datetime()](https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html) or
-
-
-### Example of default Filter selectors
-
-!!! example "Default Filter selectors"
- === "app.py"
- ```{.python pycafe-link}
- import pandas as pd
- from vizro import Vizro
- import vizro.plotly.express as px
- import vizro.models as vm
-
- df_stocks = px.data.stocks(datetimes=True)
-
- df_stocks_long = pd.melt(
- df_stocks,
- id_vars='date',
- value_vars=['GOOG', 'AAPL', 'AMZN', 'FB', 'NFLX', 'MSFT'],
- var_name='stocks',
- value_name='value'
- )
-
- df_stocks_long['value'] = df_stocks_long['value'].round(3)
-
- page = vm.Page(
- title="My first page",
- components=[
- vm.Graph(figure=px.line(df_stocks_long, x="date", y="value", color="stocks")),
- ],
- controls=[
- vm.Filter(column="stocks"),
- vm.Filter(column="value"),
- vm.Filter(column="date"),
- ],
- )
-
- dashboard = vm.Dashboard(pages=[page])
-
- Vizro().build(dashboard).run()
- ```
- === "app.yaml"
- ```yaml
- # Still requires a .py to add data to the data manager and parse YAML configuration
- # See yaml_version example
- pages:
- - components:
- - figure:
- _target_: line
- data_frame: df_stocks_long
- x: date
- y: value
- color: stocks
- type: graph
- controls:
- - column: stocks
- type: filter
- - column: value
- type: filter
- - column: date
- type: filter
- title: My first page
- ```
- === "Result"
- [![Filter]][Filter]
-
- [Filter]: ../../assets/user_guides/selectors/default_filter_selectors.png
-
-
-To enhance existing selectors, see our [how-to-guide on creating custom components](custom-components.md).
diff --git a/vizro-core/docs/pages/user-guides/table.md b/vizro-core/docs/pages/user-guides/table.md
index 19197c465..80e8e53dc 100755
--- a/vizro-core/docs/pages/user-guides/table.md
+++ b/vizro-core/docs/pages/user-guides/table.md
@@ -2,46 +2,32 @@
This guide shows you how to visualize tables in Vizro.
-There are two ways to visualize tables in Vizro, using either [AG Grid](#ag-grid) or [Dash DataTable](#dash-datatable).
-In general, [AG Grid](#ag-grid) is Vizro's recommended table implementation, but sometimes it may make sense to use the [Dash DataTable](#dash-datatable) instead.
+There are two ways to visualize tables in Vizro, using either [AG Grid](#ag-grid) or [Dash DataTable](#dash-datatable). In general, [AG Grid](#ag-grid) is Vizro's recommended table implementation, but sometimes it may make sense to use the [Dash DataTable](#dash-datatable) instead.
## Choose between AG Grid and Dash DataTable
-Vizro offers two models - the [`AgGrid`][vizro.models.AgGrid] model and the [`Table`][vizro.models.Table] model - for the above two approaches respectively.
-They both visualize tabular data in similar ways.
+Vizro offers two models - the [`AgGrid`][vizro.models.AgGrid] model and the [`Table`][vizro.models.Table] model - for the above two approaches respectively. They both visualize tabular data in similar ways.
-The main difference between the two is that the [`AgGrid`][vizro.models.AgGrid] model is based on Plotly's [Dash AG Grid](https://dash.plotly.com/dash-ag-grid) component,
-while the [`Table`][vizro.models.Table] model is based on the [Dash DataTable](https://dash.plotly.com/datatable) component.
-
-Both approaches have similar base features, and are configurable in similar ways. However, the AG Grid offers more advanced features out-of-the-box, is more customizable
-and also ships a powerful enterprise version. This is why it is Vizro's recommended table implementation. At the same time, the Dash DataTable can be used if developers are
-already familiar with it, or if some custom functionality is easier to implement using the Dash DataTable.
+The main difference between the two is that the [`AgGrid`][vizro.models.AgGrid] model is based on Plotly's [Dash AG Grid](https://dash.plotly.com/dash-ag-grid) component, while the [`Table`][vizro.models.Table] model is based on the [Dash DataTable](https://dash.plotly.com/datatable) component.
+Both approaches have similar base features, and are configurable in similar ways. However, the AG Grid offers more advanced features out-of-the-box, is more customizable and also ships a powerful enterprise version. This is why it is Vizro's recommended table implementation. At the same time, the Dash DataTable can be used if developers are already familiar with it, or if some custom functionality is easier to implement using the Dash DataTable.
## AG Grid
-[AG Grid](https://www.ag-grid.com/) is an interactive table/grid component designed for viewing, editing, and exploring large datasets. It
-is Vizro's recommended table implementation.
+[AG Grid](https://www.ag-grid.com/) is an interactive table/grid component designed for viewing, editing, and exploring large datasets. It is Vizro's recommended table implementation.
-The Vizro [`AgGrid`][vizro.models.AgGrid] model is based on the [Dash AG Grid](https://dash.plotly.com/dash-ag-grid), which is in turn based the
-original [Javascript implementation](https://www.ag-grid.com/).
+The Vizro [`AgGrid`][vizro.models.AgGrid] model is based on the [Dash AG Grid](https://dash.plotly.com/dash-ag-grid), which is in turn based the original [Javascript implementation](https://www.ag-grid.com/).
### Basic usage
To add a [`AgGrid`][vizro.models.AgGrid] to your page, do the following:
-1. Insert the [`AgGrid`][vizro.models.AgGrid] model into the `components` argument of the
-[`Page`][vizro.models.Page] model.
-2. Enter the `dash_ag_grid` function under the `figure` argument (imported via `from vizro.tables import dash_ag_grid`).
-
-The Vizro version of this AG Grid differs in one way from the original Dash AG Grid: it requires the user to pass a pandas DataFrame as the source of data.
-As explained in [our guide to using data in Vizro](data.md), this must be entered under the argument `data_frame`. Most other [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments.
-Note that some defaults are set for some arguments (for example, for `columnDefs`) to help with styling and usability.
-Sometimes a parameter may not work because it requires a callback to function. In that case you can try [creating a custom AG Grid callable](custom-tables.md).
+1. Insert the [`AgGrid`][vizro.models.AgGrid] model into the `components` argument of the [`Page`][vizro.models.Page] model.
+1. Enter the `dash_ag_grid` function under the `figure` argument (imported via `from vizro.tables import dash_ag_grid`).
+The Vizro version of this AG Grid differs in one way from the original Dash AG Grid: it requires the user to pass a pandas DataFrame as the source of data. As explained in [our guide to using data in Vizro](data.md), this must be entered under the argument `data_frame`. Most other [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments. Note that some defaults are set for some arguments (for example, for `columnDefs`) to help with styling and usability. Sometimes a parameter may not work because it requires a callback to function. In that case you can try [creating a custom AG Grid callable](custom-tables.md).
!!! example "Basic Dash AG Grid"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -59,29 +45,28 @@ Sometimes a parameter may not work because it requires a callback to function. I
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See from_yaml example
pages:
- - components:
- - figure:
- _target_: dash_ag_grid
- data_frame: gapminder
- type: ag_grid
- title: Default Dash AG Grid
+ - components:
+ - figure:
+ _target_: dash_ag_grid
+ data_frame: gapminder
+ type: ag_grid
+ title: Default Dash AG Grid
```
- === "Result"
- [![AGGrid]][AGGrid]
- [AGGrid]: ../../assets/user_guides/table/aggrid.png
+ === "Result"
+ [![AGGrid]][aggrid]
### Enable pagination
-Pagination is a visual alternative to using vertical scroll. It can also improve loading time if you have many rows.
-You can turn it on by setting `dashGridOptions={"pagination": True}`.
-!!! example "Basic Dash AG Grid"
+Pagination is a visual alternative to using vertical scroll. It can also improve loading time if you have many rows. You can turn it on by setting `dashGridOptions={"pagination": True}`.
+!!! example "Basic Dash AG Grid"
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -99,37 +84,34 @@ You can turn it on by setting `dashGridOptions={"pagination": True}`.
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See from_yaml example
pages:
- - components:
- - figure:
- _target_: dash_ag_grid
- data_frame: gapminder
- dashGridOptions:
- pagination: true
- type: ag_grid
- title: Dash AG Grid with pagination
+ - components:
+ - figure:
+ _target_: dash_ag_grid
+ data_frame: gapminder
+ dashGridOptions:
+ pagination: true
+ type: ag_grid
+ title: Dash AG Grid with pagination
```
- === "Result"
- [![AGGrid]][AGGrid]
- [AGGrid]: ../../assets/user_guides/table/aggrid-pagination.png
+ === "Result"
+ [![AGGrid]][aggrid]
### Formatting columns
#### Numbers
-One of the most common tasks when working with tables is to format the columns so that displayed numbers are more readable.
-To do this, you can use the native functionality of [value formatters](https://dash.plotly.com/dash-ag-grid/value-formatters)
-or the Vizro pre-defined [custom cell data types](https://dash.plotly.com/dash-ag-grid/cell-data-types#providing-custom-cell-data-types) as shown below.
+One of the most common tasks when working with tables is to format the columns so that displayed numbers are more readable. To do this, you can use the native functionality of [value formatters](https://dash.plotly.com/dash-ag-grid/value-formatters) or the Vizro pre-defined [custom cell data types](https://dash.plotly.com/dash-ag-grid/cell-data-types#providing-custom-cell-data-types) as shown below.
The available custom cell types for Vizro are `dollar`, `euro`, `percent` and `numeric`.
-To use these, define your desired `` alongside the chosen `cellDataType` in
-the `columnDefs` argument of your `dash_ag_grid` function:
+To use these, define your desired `` alongside the chosen `cellDataType` in the `columnDefs` argument of your `dash_ag_grid` function:
```py
columnDefs = [{"field": "", "cellDataType": "euro"}]
@@ -138,7 +120,6 @@ columnDefs = [{"field": "", "cellDataType": "euro"}]
In the example below we select and format some columns of the gapminder data.
!!! example "AG Grid with formatted columns"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -168,6 +149,7 @@ In the example below we select and format some columns of the gapminder data.
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -190,33 +172,23 @@ In the example below we select and format some columns of the gapminder data.
type: ag_grid
title: Example of AG Grid with formatted columns
```
- === "Result"
- [![AGGrid2]][AGGrid2]
- [AGGrid2]: ../../assets/user_guides/table/formatted_aggrid.png
+ === "Result"
+ [![AGGrid2]][aggrid2]
#### Dates
-For the [`AgGrid`][vizro.models.AgGrid] model to sort and filter dates correctly, the date must either be of
-string format `yyyy-mm-dd` (see [Dash AG Grid docs](https://dash.plotly.com/dash-ag-grid/date-filters#example:-date-filter))
-or a pandas datetime object. Any pandas datetime column will be transformed into the `yyyy-mm-dd` format automatically.
+For the [`AgGrid`][vizro.models.AgGrid] model to sort and filter dates correctly, the date must either be of string format `yyyy-mm-dd` (see [Dash AG Grid docs](https://dash.plotly.com/dash-ag-grid/date-filters#example:-date-filter)) or a pandas datetime object. Any pandas datetime column will be transformed into the `yyyy-mm-dd` format automatically.
#### Objects and strings
-No specific formatting is available for custom objects and strings, however you can make use of [Value Formatters](https://dash.plotly.com/dash-ag-grid/value-formatters)
-to format displayed strings automatically.
-
+No specific formatting is available for custom objects and strings, however you can make use of [Value Formatters](https://dash.plotly.com/dash-ag-grid/value-formatters) to format displayed strings automatically.
### Styling and changing the AG Grid
-As mentioned above, all [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments. Below you can find
-an example of a styled AG Grid where some conditional formatting is applied, and where the columns are editable, but
-not filterable or resizable. There are more ways to alter the grid beyond this showcase. AG Grid, like any other Vizro
-component, can be customized using custom CSS. You can find information in
-the [guide to overwriting CSS properties](custom-css.md#overwrite-css-for-selected-components).
+As mentioned above, all [parameters of the Dash AG Grid](https://dash.plotly.com/dash-ag-grid/reference) can be entered as keyword arguments. Below you can find an example of a styled AG Grid where some conditional formatting is applied, and where the columns are editable, but not filterable or resizable. There are more ways to alter the grid beyond this showcase. AG Grid, like any other Vizro component, can be customized using custom CSS. You can find information in the [guide to overwriting CSS properties](custom-css.md#overwrite-css-for-selected-components).
!!! example "Styled and modified Dash AG Grid"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -284,6 +256,7 @@ the [guide to overwriting CSS properties](custom-css.md#overwrite-css-for-select
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -299,28 +272,28 @@ the [guide to overwriting CSS properties](custom-css.md#overwrite-css-for-select
- field: year
- field: lifeExp
valueFormatter:
- function: "d3.format('.1f')(params.value)"
+ function: d3.format('.1f')(params.value)
- field: gdpPercap
valueFormatter:
- function: "d3.format('$,.1f')(params.value)"
+ function: d3.format('$,.1f')(params.value)
cellStyle:
styleConditions:
- condition: params.value < 1045
style:
- backgroundColor: "#ff9222"
+ backgroundColor: '#ff9222'
- condition: params.value >= 1045 && params.value <= 4095
style:
- backgroundColor: "#de9e75"
+ backgroundColor: '#de9e75'
- condition: params.value > 4095 && params.value <= 12695
style:
- backgroundColor: "#aaa9ba"
+ backgroundColor: '#aaa9ba'
- condition: params.value > 12695
style:
- backgroundColor: "#00b4ff"
+ backgroundColor: '#00b4ff'
- field: pop
type: rightAligned
valueFormatter:
- function: "d3.format(',.0f')(params.value)"
+ function: d3.format(',.0f')(params.value)
defaultColDef:
resizable: false
filter: false
@@ -329,10 +302,9 @@ the [guide to overwriting CSS properties](custom-css.md#overwrite-css-for-select
type: ag_grid
title: Example of a Dash AG Grid
```
- === "Result"
- [![AGGrid3]][AGGrid3]
- [AGGrid3]: ../../assets/user_guides/table/styled_aggrid.png
+ === "Result"
+ [![AGGrid3]][aggrid3]
If the available arguments are not sufficient, there is always the option to [create a custom AG Grid callable](custom-tables.md).
@@ -348,19 +320,14 @@ The Vizro [`Table`][vizro.models.Table] model is based on the [Dash DataTable](h
To add a [`Table`][vizro.models.Table] to your page, do the following:
-1. Insert the [`Table`][vizro.models.Table] model into the `components` argument of the
-[`Page`][vizro.models.Page] model.
-2. Enter the `dash_data_table` function under the `figure` argument (imported via `from vizro.tables import dash_data_table`).
-
+1. Insert the [`Table`][vizro.models.Table] model into the `components` argument of the [`Page`][vizro.models.Page] model.
+1. Enter the `dash_data_table` function under the `figure` argument (imported via `from vizro.tables import dash_data_table`).
-The Vizro version of this table differs in one way from the original table: it requires the user to pass a pandas DataFrame as the source of data.
-As explained in [our guide to using data in Vizro](data.md), this must be entered under the argument `data_frame`.
+The Vizro version of this table differs in one way from the original table: it requires the user to pass a pandas DataFrame as the source of data. As explained in [our guide to using data in Vizro](data.md), this must be entered under the argument `data_frame`.
-All other [parameters of the Dash DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Note that we are
-setting some defaults for some arguments to help with styling.
+All other [parameters of the Dash DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Note that we are setting some defaults for some arguments to help with styling.
!!! example "Dash DataTable"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -380,31 +347,29 @@ setting some defaults for some arguments to help with styling.
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: dash_data_table
- data_frame: gapminder_2007
- title: Dash DataTable
- type: table
- title: Example of a Dash DataTable
+ - components:
+ - figure:
+ _target_: dash_data_table
+ data_frame: gapminder_2007
+ title: Dash DataTable
+ type: table
+ title: Example of a Dash DataTable
```
- === "Result"
- [![Table]][Table]
- [Table]: ../../assets/user_guides/table/table.png
+ === "Result"
+ [![Table]][table]
### Styling and changing the Dash DataTable
-As mentioned above, all [parameters of the Dash DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Below you can find
-an example of a styled table where some conditional formatting is applied. There are many more ways to alter the table beyond this showcase.
+As mentioned above, all [parameters of the Dash DataTable](https://dash.plotly.com/datatable/reference) can be entered as keyword arguments. Below you can find an example of a styled table where some conditional formatting is applied. There are many more ways to alter the table beyond this showcase.
!!! example "Styled Dash DataTable"
-
=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
@@ -467,6 +432,7 @@ an example of a styled table where some conditional formatting is applied. There
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
@@ -504,12 +470,12 @@ an example of a styled table where some conditional formatting is applied. There
backgroundColor: dodgerblue
color: white
- if:
- filter_query: "{lifeExp} < 55"
+ filter_query: '{lifeExp} < 55'
column_id: lifeExp
- backgroundColor: "#85144b"
+ backgroundColor: '#85144b'
color: white
- if:
- filter_query: "{gdpPercap} > 10000"
+ filter_query: '{gdpPercap} > 10000'
column_id: gdpPercap
backgroundColor: green
color: white
@@ -524,26 +490,20 @@ an example of a styled table where some conditional formatting is applied. There
title: Dash DataTable
```
- === "Result"
- [![Table2]][Table2]
- [Table2]: ../../assets/user_guides/table/styled_table.png
+ === "Result"
+ [![Table2]][table2]
If the available arguments are not sufficient, there is always the option to create a [custom Dash DataTable](custom-tables.md).
-
## Add title, header, and footer
-The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] models accept a `title`, `header` and
-`footer` argument. This is useful for providing context to the data being displayed, or for adding a description of
-the data.
+The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] models accept a `title`, `header` and `footer` argument. This is useful for providing context to the data being displayed, or for adding a description of the data.
- **title**: Displayed as an [H3 header](https://dash.plotly.com/dash-html-components/h3), useful for summarizing the main topic or insight of the component.
- **header**: Accepts markdown text, ideal for extra descriptions, subtitles, or detailed data insights.
- **footer**: Accepts markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers.
-
-
### Formatted AgGrid
!!! example "Formatted AgGrid"
@@ -571,30 +531,29 @@ the data.
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: dash_ag_grid
- data_frame: gapminder_2007
- dashGridOptions:
- pagination: true
- title: Gapminder Data Insights
- header: |
- #### An Interactive Exploration of Global Health, Wealth, and Population
- footer: |
- SOURCE: **Plotly gapminder data set, 2024**
- type: ag_grid
- title: Formatted AgGrid
+ - components:
+ - figure:
+ _target_: dash_ag_grid
+ data_frame: gapminder_2007
+ dashGridOptions:
+ pagination: true
+ title: Gapminder Data Insights
+ header: |
+ #### An Interactive Exploration of Global Health, Wealth, and Population
+ footer: |
+ SOURCE: **Plotly gapminder data set, 2024**
+ type: ag_grid
+ title: Formatted AgGrid
```
- === "Result"
- [![FormattedGrid]][FormattedGrid]
-
- [FormattedGrid]: ../../assets/user_guides/components/formatted_aggrid.png
+ === "Result"
+ [![FormattedGrid]][formattedgrid]
### Formatted DataTable
@@ -623,24 +582,32 @@ the data.
dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: dash_data_table
- data_frame: gapminder_2007
- title: Gapminder Data Insights
- header: |
- #### An Interactive Exploration of Global Health, Wealth, and Population
- footer: |
- SOURCE: **Plotly gapminder data set, 2024**
- type: table
- title: Formatted DataTable
+ - components:
+ - figure:
+ _target_: dash_data_table
+ data_frame: gapminder_2007
+ title: Gapminder Data Insights
+ header: |
+ #### An Interactive Exploration of Global Health, Wealth, and Population
+ footer: |
+ SOURCE: **Plotly gapminder data set, 2024**
+ type: table
+ title: Formatted DataTable
```
- === "Result"
- [![FormattedTable]][FormattedTable]
- [FormattedTable]: ../../assets/user_guides/components/formatted_table.png
+ === "Result"
+ [![FormattedTable]][formattedtable]
+
+[aggrid]: ../../assets/user_guides/table/aggrid.png
+[aggrid2]: ../../assets/user_guides/table/formatted_aggrid.png
+[aggrid3]: ../../assets/user_guides/table/styled_aggrid.png
+[formattedgrid]: ../../assets/user_guides/components/formatted_aggrid.png
+[formattedtable]: ../../assets/user_guides/components/formatted_table.png
+[table]: ../../assets/user_guides/table/table.png
+[table2]: ../../assets/user_guides/table/styled_table.png
diff --git a/vizro-core/docs/pages/user-guides/tabs.md b/vizro-core/docs/pages/user-guides/tabs.md
index 09154177e..1811d0cac 100755
--- a/vizro-core/docs/pages/user-guides/tabs.md
+++ b/vizro-core/docs/pages/user-guides/tabs.md
@@ -1,8 +1,6 @@
# How to use tabs
-[`Tabs`][vizro.models.Tabs] organize and separate groups of related content in a dashboard, letting users switch between different sections or views.
-They are essentially a way of putting multiple [`Containers`][vizro.models.Container] in the same screen space, and letting the user switch between them.
-`Containers` enable the grouping of page components into sections and subsections. See our [user guide on `Containers`](container.md) for more information.
+[`Tabs`][vizro.models.Tabs] organize and separate groups of related content in a dashboard, letting users switch between different sections or views. They are essentially a way of putting multiple [`Containers`][vizro.models.Container] in the same screen space, and letting the user switch between them. `Containers` enable the grouping of page components into sections and subsections. See our [user guide on `Containers`](container.md) for more information.
![tabs](../../assets/user_guides/components/tabs-info.png){ width="400"}
@@ -16,14 +14,12 @@ This guide shows you how to use tabs to organize your `Containers` into subsecti
By using [`Tabs`][vizro.models.Tabs], the following applies:
- [`Filters`][vizro.models.Filter] affect all components on all tabs (opened and closed) of the page if not specified otherwise inside `Filter.targets`
-- The `title` of the [`Container`][vizro.models.Container] inserted into `Tabs.tabs` will be displayed as a tab label, and the title will be removed from the `Container`
-
+- The `title` of the [`Container`][vizro.models.Container] inserted into `Tabs.tabs` will be displayed as a tab label, and the title will be removed from the `Container`
To add [`Tabs`][vizro.models.Tabs] to your page, do the following:
1. Insert the [`Tabs`][vizro.models.Tabs] into the `components` argument of the [`Page`][vizro.models.Page]
-2. Insert your [`Containers`][vizro.models.Container] into the `tabs` argument of the [`Tabs`][vizro.models.Tabs]
-
+1. Insert your [`Containers`][vizro.models.Container] into the `tabs` argument of the [`Tabs`][vizro.models.Tabs]
!!! example "Tabs"
=== "app.py"
@@ -88,52 +84,53 @@ To add [`Tabs`][vizro.models.Tabs] to your page, do the following:
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See from_yaml example
pages:
- - components:
- - tabs:
- - title: Tab I
- type: container
- components:
- - type: graph
- figure:
- _target_: bar
- data_frame: gapminder_2007
- title: Graph 1
- x: continent
- y: lifeExp
- color: continent
- - type: graph
- figure:
- _target_: box
- data_frame: gapminder_2007
- title: Graph 2
- x: continent
- y: lifeExp
- color: continent
- - title: Tab II
- type: container
- components:
- - type: graph
- figure:
- _target_: scatter
- data_frame: gapminder_2007
- title: Graph 3
- x: gdpPercap
- y: lifeExp
- size: pop
- color: continent
- type: tabs
+ components:
+ - type: tabs
+ tabs:
+ - title: Tab I
+ type: container
+ components:
+ - type: graph
+ figure:
+ _target_: bar
+ data_frame: gapminder_2007
+ title: Graph 1
+ x: continent
+ y: lifeExp
+ color: continent
+ - type: graph
+ figure:
+ _target_: box
+ data_frame: gapminder_2007
+ title: Graph 2
+ x: continent
+ y: lifeExp
+ color: continent
+ - title: Tab II
+ type: container
+ components:
+ - type: graph
+ figure:
+ _target_: scatter
+ data_frame: gapminder_2007
+ title: Graph 3
+ x: gdpPercap
+ y: lifeExp
+ size: pop
+ color: continent
controls:
- - type: filter
- column: continent
+ - type: filter
+ column: continent
title: Tabs
```
- === "Result"
- [![Tabs]][Tabs]
+ === "Result"
+ [![Tabs]][tabs]
- [Tabs]: ../../assets/user_guides/components/tabs.png
+[tabs]: ../../assets/user_guides/components/tabs.png
diff --git a/vizro-core/docs/pages/user-guides/themes.md b/vizro-core/docs/pages/user-guides/themes.md
index 6f78441d5..ac1d6fc7b 100644
--- a/vizro-core/docs/pages/user-guides/themes.md
+++ b/vizro-core/docs/pages/user-guides/themes.md
@@ -1,15 +1,13 @@
# How to use themes
-This guide shows you how to use themes. Themes are pre-designed collections of stylings that are applied to entire charts and dashboards.
-The themes provided by Vizro are infused with our design best practices that make charts and dashboards look visually consistent and professional.
+This guide shows you how to use themes. Themes are pre-designed collections of stylings that are applied to entire charts and dashboards. The themes provided by Vizro are infused with our design best practices that make charts and dashboards look visually consistent and professional.
## Themes in dashboards
-The [`Dashboard`][vizro.models.Dashboard] model accepts an optional `theme` argument, where you can choose between
-a `vizro_dark` and a `vizro_light` theme. If not specified then `theme` defaults to `vizro_dark`. The theme is applied to the entire dashboard and its charts/components when a user first loads your dashboard. Regardless of the theme applied on first load, users can always switch between light and dark themes via the toggle button in the upper-right corner of the dashboard.
+
+The [`Dashboard`][vizro.models.Dashboard] model accepts an optional `theme` argument, where you can choose between a `vizro_dark` and a `vizro_light` theme. If not specified then `theme` defaults to `vizro_dark`. The theme is applied to the entire dashboard and its charts/components when a user first loads your dashboard. Regardless of the theme applied on first load, users can always switch between light and dark themes via the toggle button in the upper-right corner of the dashboard.
!!! example "Change theme"
=== "app.py"
-
```{.python pycafe-link hl_lines="18"}
import vizro.models as vm
import vizro.plotly.express as px
@@ -32,47 +30,40 @@ a `vizro_dark` and a `vizro_light` theme. If not specified then `theme` defaults
Vizro().build(dashboard).run()
```
+
=== "app.yaml"
```yaml hl_lines="12"
# Still requires a .py to add data to the data manager and parse YAML configuration
# See yaml_version example
pages:
- - components:
- - figure:
- _target_: scatter_matrix
- color: species
- data_frame: iris
- dimensions: ["sepal_length", "sepal_width", "petal_length", "petal_width"]
- type: graph
- title: Changing themes
+ - components:
+ - figure:
+ _target_: scatter_matrix
+ color: species
+ data_frame: iris
+ dimensions: [sepal_length, sepal_width, petal_length, petal_width]
+ type: graph
+ title: Changing themes
theme: vizro_light
```
+
=== "Result - vizro_light"
- [![Light]][Light]
+ [![Light]][light]
- [Light]: ../../assets/user_guides/themes/light.png
=== "Result - vizro_dark"
- [![Dark]][Dark]
-
- [Dark]: ../../assets/user_guides/themes/dark.png
-
+ [![Dark]][dark]
## Themes in plotly charts
You can also use our templates for plotly charts outside the dashboard. This is useful in a few contexts:
-* Creation of standalone charts to be used independently of a Vizro dashboard.
-* Rapid development of charts for eventual use in a Vizro dashboard, for example in a Jupyter Notebook.
+- Creation of standalone charts to be used independently of a Vizro dashboard.
+- Rapid development of charts for eventual use in a Vizro dashboard, for example in a Jupyter Notebook.
!!! note
+ Using `import vizro.plotly.express as px` is equal to using `import plotly.express as px`, but with the added benefit of being able to integrate the resulting chart code into a Vizro dashboard. Vizro offers a minimal layer on top of Plotly's existing charting library, allowing you to seamlessly use all the existing charts and functionalities provided by plotly.express without any modifications.
- Using `import vizro.plotly.express as px` is equivalent to using `import plotly.express as px`,
- but with the added benefit of being able to integrate the resulting chart code into a Vizro dashboard.
- Vizro offers a minimal layer on top of Plotly's existing charting library, allowing you to seamlessly use all the
- existing charts and functionalities provided by plotly.express without any modifications.
-
-Our `vizro_dark` and `vizro_light` themes are automatically registered to `plotly.io.templates` when importing Vizro.
-Consult the plotly documentation for [more details on how templates work in plotly](https://plotly.com/python/templates/#theming-and-templates).
+Our `vizro_dark` and `vizro_light` themes are automatically registered to `plotly.io.templates` when importing Vizro. Consult the plotly documentation for [more details on how templates work in plotly](https://plotly.com/python/templates/#theming-and-templates).
By default, plots imported from `vizro.plotly.express` have the `vizro_dark` theme applied. This can be altered either globally or for individual plots.
@@ -87,14 +78,20 @@ pio.templates.default = "vizro_light"
```
### Set themes for selected charts
+
To change the template for a selected chart only, use the `template` parameter and run:
```python
import vizro.plotly.express as px
df = px.data.iris()
-px.scatter_matrix(df,
- dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"],
- color="species",
- template="vizro_light")
+px.scatter_matrix(
+ df,
+ dimensions=["sepal_length", "sepal_width", "petal_length", "petal_width"],
+ color="species",
+ template="vizro_light",
+)
```
+
+[dark]: ../../assets/user_guides/themes/dark.png
+[light]: ../../assets/user_guides/themes/light.png
diff --git a/vizro-core/docs/pages/user-guides/visual-formatting.md b/vizro-core/docs/pages/user-guides/visual-formatting.md
index 7b384f3e9..56d1d2d52 100644
--- a/vizro-core/docs/pages/user-guides/visual-formatting.md
+++ b/vizro-core/docs/pages/user-guides/visual-formatting.md
@@ -1,17 +1,13 @@
# How to customize the style of Vizro dashboards
-Vizro has a default styling to help users with no design experience get started.
-There are several options if you want to customize the style:
+Vizro has a default styling to help users with no design experience get started. There are several options if you want to customize the style:
-* **[Configure the `Layout`](layouts.md)**: Customize the arrangement of your components inside your Vizro dashboard.
+- **[Configure the `Layout`](layouts.md)**: Customize the arrangement of your components inside your Vizro dashboard.
-* **[Apply a theme](themes.md)**: Choose between a dark or light theme.
+- **[Apply a theme](themes.md)**: Choose between a dark or light theme.
-* **[Manage assets](assets.md)**: Enhance your dashboard by adding images, scripts, and stylesheets to your assets folder.
+- **[Manage assets](assets.md)**: Enhance your dashboard by adding images, scripts, and stylesheets to your assets folder.
-* **[Customize CSS](custom-css.md)**: Incorporate custom CSS to deviate from the default styling and create a
-unique appearance for your Vizro dashboard.
+- **[Customize CSS](custom-css.md)**: Incorporate custom CSS to deviate from the default styling and create a unique appearance for your Vizro dashboard.
-* **[Customize your `component`](components.md)**: Change the appearance of components like the [Graph](graph.md), the
-[Table](table.md) and the [AgGrid](table.md), by passing extra arguments. Refer to the relevant user guide for
-more details.
+- **[Customize your `component`](components.md)**: Change the appearance of components like the [Graph](graph.md), the [Table](table.md) and the [AgGrid](table.md), by passing extra arguments. Refer to the relevant user guide for more details.
diff --git a/vizro-core/examples/README.md b/vizro-core/examples/README.md
index 72146bfb7..53cf932b7 100644
--- a/vizro-core/examples/README.md
+++ b/vizro-core/examples/README.md
@@ -4,8 +4,7 @@ Please note that this folder contains only example dashboards that are still **i
### Vizro examples gallery
-To view a comprehensive list of available demos, please visit our [examples gallery](http://vizro.mckinsey.com/).
-There, you can explore a wide range of dashboards and applications created with Vizro.
+To view a comprehensive list of available demos, please visit our [examples gallery](http://vizro.mckinsey.com/). There, you can explore a wide range of dashboards and applications created with Vizro.
diff --git a/vizro-core/examples/dev/app.py b/vizro-core/examples/dev/app.py
index aa56f9ff1..1265ab20c 100644
--- a/vizro-core/examples/dev/app.py
+++ b/vizro-core/examples/dev/app.py
@@ -8,7 +8,7 @@
import plotly.graph_objects as go
import vizro.models as vm
import vizro.plotly.express as px
-from dash import dash_table, dcc, html
+from dash import dash_table, dcc, get_asset_url, html
from vizro import Vizro
from vizro.actions import export_data, filter_interaction
from vizro.figures import kpi_card, kpi_card_reference
@@ -606,10 +606,10 @@ def my_custom_table(data_frame=None, chosen_columns: Optional[list[str]] = None)
columns = [{"name": i, "id": i} for i in chosen_columns]
defaults = {
"style_as_list_view": True,
- "style_data": {"border_bottom": "1px solid var(--border-subtle-alpha-01)", "height": "40px"},
+ "style_data": {"border_bottom": "1px solid var(--border-subtleAlpha01)", "height": "40px"},
"style_header": {
- "border_bottom": "1px solid var(--state-overlays-selected-hover)",
- "border_top": "1px solid var(--main-container-bg-color)",
+ "border_bottom": "1px solid var(--stateOverlays-selectedHover)",
+ "border_top": "1px solid var(--right-side-bg)",
"height": "32px",
},
}
@@ -817,5 +817,16 @@ def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html.
),
)
+
if __name__ == "__main__":
- Vizro().build(dashboard).run()
+ app = Vizro().build(dashboard)
+ app.dash.layout.children.append(
+ dbc.NavLink(
+ ["Made with ", html.Img(src=get_asset_url("logo.svg"), id="banner", alt="Vizro logo"), "vizro"],
+ href="https://github.com/mckinsey/vizro",
+ target="_blank",
+ className="anchor-container",
+ )
+ )
+ server = app.dash.server
+ app.run()
diff --git a/vizro-core/examples/dev/assets/images/app.svg b/vizro-core/examples/dev/assets/app.svg
similarity index 100%
rename from vizro-core/examples/dev/assets/images/app.svg
rename to vizro-core/examples/dev/assets/app.svg
diff --git a/vizro-core/examples/dev/assets/css/custom.css b/vizro-core/examples/dev/assets/css/custom.css
index f6c0002d2..749289dba 100644
--- a/vizro-core/examples/dev/assets/css/custom.css
+++ b/vizro-core/examples/dev/assets/css/custom.css
@@ -17,3 +17,34 @@
height: 210px;
width: 240px;
}
+
+.anchor-container {
+ align-items: center;
+ background: var(--text-primary);
+ border-top-left-radius: 8px;
+ bottom: 0;
+ color: var(--text-primary-inverted);
+ display: flex;
+ font-size: 0.8rem;
+ font-weight: 500;
+ height: 24px;
+ padding: 0 12px;
+ position: fixed;
+ right: 0;
+}
+
+.anchor-container:focus,
+.anchor-container:hover {
+ background: var(--text-secondary);
+ color: var(--text-primary-inverted);
+}
+
+img#banner {
+ height: 16px;
+}
+
+img[src*="icon-top"] {
+ filter: var(--fill-icon-image-card);
+ height: 36px;
+ width: 36px;
+}
diff --git a/vizro-core/examples/dev/assets/images/logo.svg b/vizro-core/examples/dev/assets/logo.svg
similarity index 100%
rename from vizro-core/examples/dev/assets/images/logo.svg
rename to vizro-core/examples/dev/assets/logo.svg
diff --git a/vizro-core/examples/dev/requirements.in b/vizro-core/examples/dev/requirements.in
new file mode 100644
index 000000000..e6027a462
--- /dev/null
+++ b/vizro-core/examples/dev/requirements.in
@@ -0,0 +1,4 @@
+# This file is only used if you don't have hatch installed.
+gunicorn
+openpyxl
+vizro==0.1.28
diff --git a/vizro-core/examples/dev/requirements.txt b/vizro-core/examples/dev/requirements.txt
new file mode 100644
index 000000000..f43e7125e
--- /dev/null
+++ b/vizro-core/examples/dev/requirements.txt
@@ -0,0 +1,130 @@
+# This file was autogenerated by uv via the following command:
+# uv pip compile requirements.in -o requirements.txt
+annotated-types==0.7.0
+ # via pydantic
+autoflake==2.3.1
+ # via vizro
+black==24.4.2
+ # via vizro
+blinker==1.8.2
+ # via flask
+cachelib==0.9.0
+ # via flask-caching
+certifi==2024.8.30
+ # via requests
+charset-normalizer==3.4.0
+ # via requests
+click==8.1.7
+ # via
+ # black
+ # flask
+dash==2.18.1
+ # via
+ # dash-ag-grid
+ # dash-bootstrap-components
+ # vizro
+dash-ag-grid==31.2.0
+ # via vizro
+dash-bootstrap-components==1.6.0
+ # via vizro
+dash-core-components==2.0.0
+ # via dash
+dash-html-components==2.0.0
+ # via dash
+dash-mantine-components==0.12.1
+ # via vizro
+dash-table==5.0.0
+ # via dash
+et-xmlfile==2.0.0
+ # via openpyxl
+flask==3.0.3
+ # via
+ # dash
+ # flask-caching
+flask-caching==2.3.0
+ # via vizro
+gunicorn==23.0.0
+ # via -r requirements.in
+idna==3.10
+ # via requests
+importlib-metadata==8.5.0
+ # via
+ # dash
+ # flask
+itsdangerous==2.2.0
+ # via flask
+jinja2==3.1.4
+ # via flask
+markupsafe==3.0.2
+ # via
+ # jinja2
+ # werkzeug
+mypy-extensions==1.0.0
+ # via black
+nest-asyncio==1.6.0
+ # via dash
+numpy==2.0.2
+ # via pandas
+openpyxl==3.1.5
+ # via -r requirements.in
+packaging==24.1
+ # via
+ # black
+ # gunicorn
+ # plotly
+pandas==2.2.3
+ # via vizro
+pathspec==0.12.1
+ # via black
+platformdirs==4.2.2
+ # via black
+plotly==5.24.1
+ # via
+ # dash
+ # vizro
+pydantic==2.9.2
+ # via vizro
+pydantic-core==2.23.4
+ # via pydantic
+pyflakes==3.2.0
+ # via autoflake
+python-dateutil==2.9.0.post0
+ # via pandas
+pytz==2024.2
+ # via pandas
+requests==2.32.3
+ # via dash
+retrying==1.3.4
+ # via dash
+setuptools==75.3.0
+ # via dash
+six==1.16.0
+ # via
+ # python-dateutil
+ # retrying
+tenacity==9.0.0
+ # via plotly
+tomli==2.1.0
+ # via
+ # autoflake
+ # black
+typing-extensions==4.12.2
+ # via
+ # black
+ # dash
+ # pydantic
+ # pydantic-core
+tzdata==2024.2
+ # via pandas
+urllib3==2.2.3
+ # via requests
+vizro==0.1.28
+ # via -r requirements.in
+werkzeug==3.0.6
+ # via
+ # dash
+ # flask
+wrapt==1.16.0
+ # via vizro
+zipp==3.20.2
+ # via importlib-metadata
diff --git a/vizro-core/examples/scratch_dev/app.py b/vizro-core/examples/scratch_dev/app.py
index 84e70e6aa..56413e831 100644
--- a/vizro-core/examples/scratch_dev/app.py
+++ b/vizro-core/examples/scratch_dev/app.py
@@ -1,49 +1,89 @@
"""Dev app to try things out."""
-import pandas as pd
+from vizro import Vizro
import vizro.models as vm
import vizro.plotly.express as px
-from vizro import Vizro
-from vizro._themes._color_values import COLORS
-pastry = pd.DataFrame(
- {
- "pastry": [
- "Scones",
- "Bagels",
- "Muffins",
- "Cakes",
- "Donuts",
- "Cookies",
- "Croissants",
- "Eclairs",
- "Brownies",
- "Tarts",
- "Macarons",
- "Pies",
- ],
- "Profit Ratio": [-0.10, -0.15, -0.05, 0.10, 0.05, 0.20, 0.15, -0.08, 0.08, -0.12, 0.02, -0.07],
- }
+df = px.data.gapminder()
+gapminder_data = (
+ df.groupby(by=["continent", "year"]).agg({"lifeExp": "mean", "pop": "sum", "gdpPercap": "mean"}).reset_index()
+)
+first_page = vm.Page(
+ title="First Page",
+ layout=vm.Layout(grid=[[0, 0], [1, 2], [1, 2], [1, 2]]),
+ components=[
+ vm.Card(
+ text="""
+ # First dashboard page
+ This pages shows the inclusion of markdown text in a page and how components
+ can be structured using Layout.
+ """,
+ ),
+ vm.Graph(
+ id="box_cont",
+ figure=px.box(
+ gapminder_data,
+ x="continent",
+ y="lifeExp",
+ color="continent",
+ labels={"lifeExp": "Life Expectancy", "continent": "Continent"},
+ ),
+ ),
+ vm.Graph(
+ id="line_gdp",
+ figure=px.line(
+ gapminder_data,
+ x="year",
+ y="gdpPercap",
+ color="continent",
+ labels={"year": "Year", "continent": "Continent", "gdpPercap": "GDP Per Cap"},
+ ),
+ ),
+ ],
+ controls=[
+ vm.Filter(column="continent", targets=["box_cont", "line_gdp"]),
+ ],
)
-
-page = vm.Page(
- title="Charts UI",
+iris_data = px.data.iris()
+second_page = vm.Page(
+ title="Second Page",
components=[
vm.Graph(
- figure=px.bar(
- pastry.sort_values("Profit Ratio"),
- orientation="h",
- x="Profit Ratio",
- y="pastry",
- color="Profit Ratio",
- color_continuous_scale=COLORS["DIVERGING_RED_CYAN"],
+ id="scatter_iris",
+ figure=px.scatter(
+ iris_data,
+ x="sepal_width",
+ y="sepal_length",
+ color="species",
+ color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"},
+ labels={"sepal_width": "Sepal Width", "sepal_length": "Sepal Length", "species": "Species"},
+ ),
+ ),
+ vm.Graph(
+ id="hist_iris",
+ figure=px.histogram(
+ iris_data,
+ x="sepal_width",
+ color="species",
+ color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"},
+ labels={"sepal_width": "Sepal Width", "count": "Count", "species": "Species"},
),
),
],
+ controls=[
+ vm.Parameter(
+ targets=["scatter_iris.color_discrete_map.virginica", "hist_iris.color_discrete_map.virginica"],
+ selector=vm.Dropdown(options=["#ff5267", "#3949ab"], multi=False, value="#3949ab", title="Color Virginica"),
+ ),
+ vm.Parameter(
+ targets=["scatter_iris.opacity"],
+ selector=vm.Slider(min=0, max=1, value=0.8, title="Opacity"),
+ ),
+ ],
)
-dashboard = vm.Dashboard(pages=[page])
+dashboard = vm.Dashboard(pages=[first_page, second_page])
if __name__ == "__main__":
Vizro().build(dashboard).run()
diff --git a/vizro-core/examples/scratch_dev/data.yaml b/vizro-core/examples/scratch_dev/data.yaml
new file mode 100644
index 000000000..d8b0aea90
--- /dev/null
+++ b/vizro-core/examples/scratch_dev/data.yaml
@@ -0,0 +1,12 @@
+# Choose between 0-50
+setosa: 5
+versicolor: 10
+virginica: 15
+
+# Choose between: 4.3 to 7.4
+min: 5
+max: 7
+
+# Choose between: 2020-01-01 to 2020-05-29
+date_min: 2024-01-01
+date_max: 2024-05-29
diff --git a/vizro-core/examples/visual-vocabulary/README.md b/vizro-core/examples/visual-vocabulary/README.md
index 667742e8c..e59b3103c 100644
--- a/vizro-core/examples/visual-vocabulary/README.md
+++ b/vizro-core/examples/visual-vocabulary/README.md
@@ -2,14 +2,11 @@
### Welcome to our visual vocabulary dashboard! 🎨
-This dashboard serves as a comprehensive guide for selecting and creating various types of charts. It helps you decide
-when to use each chart type, and offers sample Python code using [Plotly](https://plotly.com/python/), and
-instructions for embedding these charts into a [Vizro](https://github.com/mckinsey/vizro) dashboard.
+This dashboard serves as a comprehensive guide for selecting and creating various types of charts. It helps you decide when to use each chart type, and offers sample Python code using [Plotly](https://plotly.com/python/), and instructions for embedding these charts into a [Vizro](https://github.com/mckinsey/vizro) dashboard.
The charts in this dashboard are designed to make it easy for anyone to create beautiful and sophisticated visuals.
-Our goal is to help you understand best practices in data visualization, ensure your charts effectively communicate
-your message, and streamline the creation of high-quality, interactive visualizations.
+Our goal is to help you understand best practices in data visualization, ensure your charts effectively communicate your message, and streamline the creation of high-quality, interactive visualizations.
Created by:
@@ -19,12 +16,9 @@ Created by:
Inspired by:
-- [The FT Visual Vocabulary](https://github.com/Financial-Times/chart-doctor/blob/main/visual-vocabulary/README.md):
- [Alan Smith](https://github.com/alansmithy), [Chris Campbell](https://github.com/digitalcampbell), Ian Bott,
- Liz Faunce, Graham Parrish, Billy Ehrenberg, Paul McCallum, [Martin Stabe](https://github.com/martinstabe).
+- [The FT Visual Vocabulary](https://github.com/Financial-Times/chart-doctor/blob/main/visual-vocabulary/README.md): [Alan Smith](https://github.com/alansmithy), [Chris Campbell](https://github.com/digitalcampbell), Ian Bott, Liz Faunce, Graham Parrish, Billy Ehrenberg, Paul McCallum, [Martin Stabe](https://github.com/martinstabe).
-- [The Graphic Continuum](https://www.informationisbeautifulawards.com/showcase/611-the-graphic-continuum):
- Jon Swabish and Severino Ribecca
+- [The Graphic Continuum](https://www.informationisbeautifulawards.com/showcase/611-the-graphic-continuum): Jon Swabish and Severino Ribecca
Credits and sources:
@@ -36,80 +30,78 @@ Credits and sources:
The dashboard is still in development. Below is an overview of the chart types for which a completed page is available.
-| Chart Type | Status | Category | Credits & sources | API |
-| --------------------- | ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Arc | ❌ | Part-to-whole | | |
-| Area | ✅ | Time | [Filled area plot with px](https://plotly.com/python/filled-area-plots/) | [px.area](https://plotly.com/python-api-reference/generated/plotly.express.area) |
-| Bar | ✅ | Magnitude | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) |
-| Barcode | ❌ | Distribution | | |
-| Beeswarm | ❌ | Distribution | | |
-| Boxplot | ✅ | Distribution | [Box plot with px](https://plotly.com/python/box-plots/) | [px.box](https://plotly.github.io/plotly.py-docs/generated/plotly.express.box) |
-| Bubble | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) |
-| Bubble map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) |
-| Bubble timeline | ❌ | Time | | |
-| Bullet | ❌ | Magnitude | | |
-| Bump | ❌ | Ranking | | |
-| Butterfly | ✅ | Deviation, Distribution | [Pyramid charts in Plotly](https://plotly.com/python/v3/population-pyramid-charts/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) |
-| Chord | ❌ | Flow | | |
-| Choropleth | ✅ | Spatial | [Choropleth map with px](https://plotly.com/python/choropleth-maps/) | [px.choropleth](https://plotly.github.io/plotly.py-docs/generated/plotly.express.choropleth.html) |
-| Column | ✅ | Magnitude, Time | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
-| Column and line | ✅ | Correlation, Time | [Multiple chart types in Plotly](https://plotly.com/python/graphing-multiple-chart-types/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) and [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html) |
-| Connected scatter | ✅ | Correlation, Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
-| Cumulative curve | ❌ | Distribution | | |
-| Diverging bar | ✅ | Deviation | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) |
-| Diverging stacked bar | ✅ | Deviation | [Plotly forum - diverging stacked bar](https://community.plotly.com/t/need-help-in-making-diverging-stacked-bar-charts/34023/2) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) |
-| Donut | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) |
-| Dot map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) |
-| Dumbbell | ✅ | Distribution | [Dumbbell plots in Plotly](https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html) and [add_shape](https://plotly.com/python/shapes/) |
-| Fan | ❌ | Time | | |
-| Flow map | ❌ | Spatial | | |
-| Funnel | ✅ | Part-to-whole | [Funnel plot with px](https://plotly.com/python/funnel-charts/) | [px.funnel](https://plotly.com/python/funnel-charts/) |
-| Gantt | ✅ | Time | [Gantt chart with px](https://plotly.com/python/gantt/) | [px.timeline](https://plotly.com/python-api-reference/generated/plotly.express.timeline.html) |
-| Gridplot | ❌ | Part-to-whole | | |
-| Heatmap | ✅ | Time | [Heatmaps with px](https://plotly.com/python/heatmaps/) | [px.density_heatmap](https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html) |
-| Correlation matrix | ❌ | Correlation | | |
-| Histogram | ✅ | Distribution | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
-| Line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
-| Lollipop | ❌ | Ranking, Magnitude | | |
-| Marimekko | ❌ | Magnitude, Part-to-whole | | |
-| Network | ❌ | Flow | | |
-| Ordered bar | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
-| Ordered bubble | ❌ | Ranking | | |
-| Ordered column | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
-| Paired bar | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
-| Paired column | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
-| Parallel coordinates | ✅ | Magnitude | [Parallel coordinates plot with px](https://plotly.com/python/parallel-coordinates-plot/) | [px.parallel_coordinates](https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html) |
-| Pictogram | ❌ | Magnitude | | |
-| Pie | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) |
-| Radar | ✅ | Magnitude | [Radar chart with px](https://plotly.com/python/radar-chart/) | [px.line_polar](https://plotly.com/python-api-reference/generated/plotly.express.line_polar) |
-| Radial | ❌ | Magnitude | | |
-| Sankey | ✅ | Flow | [Sankey diagram in Plotly](https://plotly.com/python/sankey-diagram/) | [go.Sankey](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Sankey.html) |
-| Scatter | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) |
-| Scatter matrix | ✅ | Correlation | [Scatter matrix with px](https://plotly.com/python/splom/) | [px.scatter_matrix](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_matrix.html) |
-| Slope | ❌ | Ranking, Time | | |
-| Sparkline | ❌ | Time | | |
-| Stacked bar | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
-| Stacked column | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
-| Stepped line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
-| Surplus deficit line | ❌ | Deviation | | |
-| Treemap | ✅ | Part-to-whole | [Treemap with px](https://plotly.com/python/treemaps/) | [px.treemap](https://plotly.com/python-api-reference/generated/plotly.express.treemap.html) |
-| Venn | ❌ | Part-to-whole | | |
-| Violin | ✅ | Distribution | [Violin plot with px](https://plotly.com/python/violin/) | [px.violin](https://plotly.com/python-api-reference/generated/plotly.express.violin.html) |
-| Waterfall | ✅ | Part-to-whole, Flow | [Waterfall charts in Plotly](https://plotly.com/python/waterfall-charts/) | [go.Waterfall](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Waterfall.html) |
+| Chart Type | Done | Category | Credits & sources | API |
+| --------------------- | ---- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Arc | ❌ | Part-to-whole | | |
+| Area | ✅ | Time | [Filled area plot with px](https://plotly.com/python/filled-area-plots/) | [px.area](https://plotly.com/python-api-reference/generated/plotly.express.area) |
+| Bar | ✅ | Magnitude | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) |
+| Barcode | ❌ | Distribution | | |
+| Beeswarm | ❌ | Distribution | | |
+| Boxplot | ✅ | Distribution | [Box plot with px](https://plotly.com/python/box-plots/) | [px.box](https://plotly.github.io/plotly.py-docs/generated/plotly.express.box) |
+| Bubble | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) |
+| Bubble map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) |
+| Bubble timeline | ❌ | Time | | |
+| Bullet | ❌ | Magnitude | | |
+| Bump | ❌ | Ranking | | |
+| Butterfly | ✅ | Deviation, Distribution | [Pyramid charts in Plotly](https://plotly.com/python/v3/population-pyramid-charts/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) |
+| Chord | ❌ | Flow | | |
+| Choropleth | ✅ | Spatial | [Choropleth map with px](https://plotly.com/python/choropleth-maps/) | [px.choropleth](https://plotly.github.io/plotly.py-docs/generated/plotly.express.choropleth.html) |
+| Column | ✅ | Magnitude, Time | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
+| Column and line | ✅ | Correlation, Time | [Multiple chart types in Plotly](https://plotly.com/python/graphing-multiple-chart-types/) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) and [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html) |
+| Connected scatter | ✅ | Correlation, Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
+| Cumulative curve | ❌ | Distribution | | |
+| Diverging bar | ✅ | Deviation | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar) |
+| Diverging stacked bar | ✅ | Deviation | [Plotly forum - diverging stacked bar](https://community.plotly.com/t/need-help-in-making-diverging-stacked-bar-charts/34023/2) | [go.Bar](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Bar.html) |
+| Donut | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) |
+| Dot map | ✅ | Spatial | [Bubble map in px](https://plotly.com/python/bubble-maps/) | [px.scatter_map](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_map) |
+| Dumbbell | ✅ | Distribution | [Dumbbell plots in Plotly](https://community.plotly.com/t/how-to-make-dumbbell-plots-in-plotly-python/47762) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html) and [add_shape](https://plotly.com/python/shapes/) |
+| Fan | ❌ | Time | | |
+| Flow map | ❌ | Spatial | | |
+| Funnel | ✅ | Part-to-whole | [Funnel plot with px](https://plotly.com/python/funnel-charts/) | [px.funnel](https://plotly.com/python/funnel-charts/) |
+| Gantt | ✅ | Time | [Gantt chart with px](https://plotly.com/python/gantt/) | [px.timeline](https://plotly.com/python-api-reference/generated/plotly.express.timeline.html) |
+| Gridplot | ❌ | Part-to-whole | | |
+| Heatmap | ✅ | Time | [Heatmaps with px](https://plotly.com/python/heatmaps/) | [px.density_heatmap](https://plotly.com/python-api-reference/generated/plotly.express.density_heatmap.html) |
+| Correlation matrix | ❌ | Correlation | | |
+| Histogram | ✅ | Distribution | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
+| Line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
+| Lollipop | ✅ | Ranking, Magnitude | [Lollipop & Dumbbell Charts with Plotly](https://towardsdatascience.com/lollipop-dumbbell-charts-with-plotly-696039d5f85) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) |
+| Marimekko | ❌ | Magnitude, Part-to-whole | | |
+| Network | ❌ | Flow | | |
+| Ordered bar | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
+| Ordered bubble | ❌ | Ranking | | |
+| Ordered column | ✅ | Ranking | [Bar chart with px](https://plotly.com/python/bar-charts/) | [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) |
+| Paired bar | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
+| Paired column | ✅ | Magnitude | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
+| Parallel coordinates | ✅ | Magnitude | [Parallel coordinates plot with px](https://plotly.com/python/parallel-coordinates-plot/) | [px.parallel_coordinates](https://plotly.com/python-api-reference/generated/plotly.express.parallel_coordinates.html) |
+| Pictogram | ❌ | Magnitude | | |
+| Pie | ✅ | Part-to-whole | [Pie chart with px](https://plotly.com/python/pie-charts/) | [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie) |
+| Radar | ✅ | Magnitude | [Radar chart with px](https://plotly.com/python/radar-chart/) | [px.line_polar](https://plotly.com/python-api-reference/generated/plotly.express.line_polar) |
+| Radial | ❌ | Magnitude | | |
+| Sankey | ✅ | Flow | [Sankey diagram in Plotly](https://plotly.com/python/sankey-diagram/) | [go.Sankey](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Sankey.html) |
+| Scatter | ✅ | Correlation | [Scatter plot with px](https://plotly.com/python/line-and-scatter/) | [px.scatter](https://plotly.com/python-api-reference/generated/plotly.express.scatter) |
+| Scatter matrix | ✅ | Correlation | [Scatter matrix with px](https://plotly.com/python/splom/) | [px.scatter_matrix](https://plotly.github.io/plotly.py-docs/generated/plotly.express.scatter_matrix.html) |
+| Slope | ❌ | Ranking, Time | | |
+| Sparkline | ✅ | Time | [Sparklines with px](https://plotly.com/python/line-charts/#sparklines-with-plotly-express) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) or [px.area](https://plotly.com/python-api-reference/generated/plotly.express.area) |
+| Stacked bar | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
+| Stacked column | ✅ | Part-to-whole | [Histograms with px](https://plotly.com/python/histograms/) | [px.histogram](https://plotly.github.io/plotly.py-docs/generated/plotly.express.histogram) |
+| Stepped line | ✅ | Time | [Line plot with px](https://plotly.com/python/line-charts/) | [px.line](https://plotly.com/python-api-reference/generated/plotly.express.line) |
+| Surplus deficit line | ❌ | Deviation | | |
+| Treemap | ✅ | Part-to-whole | [Treemap with px](https://plotly.com/python/treemaps/) | [px.treemap](https://plotly.com/python-api-reference/generated/plotly.express.treemap.html) |
+| Venn | ❌ | Part-to-whole | | |
+| Violin | ✅ | Distribution | [Violin plot with px](https://plotly.com/python/violin/) | [px.violin](https://plotly.com/python-api-reference/generated/plotly.express.violin.html) |
+| Waterfall | ✅ | Part-to-whole, Flow | [Waterfall charts in Plotly](https://plotly.com/python/waterfall-charts/) | [go.Waterfall](https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Waterfall.html) |
## How to contribute
Contributions are welcome! To contribute a chart, follow the steps below:
1. Check that a `svg` file named after the chart type is contained in the [assets](https://github.com/mckinsey/vizro/tree/main/vizro-core/examples/visual-vocabulary/assets/images/charts) folder. If not, [raise an issue](https://github.com/mckinsey/vizro/issues) in the repository.
-2. Add the data set to `_pages_utils.py` if it doesn't already exist. Use existing data sets preferably or any other data set that is publicly available e.g. [plotly.express.data](https://plotly.com/python-api-reference/generated/plotly.express.data.html)
-3. Create a new page for the chart type and add it to the relevant category `.py` file such as `correlation.py`,
- `deviation.py`, `distribution.py`, etc. Ensure you add the page to the list of `pages` at the end of the `.py` file.
-4. Add a `.py` file containing a code example of the chart type in the `pages/examples` folder, for instance, `area.py`. Take a look at existing examples.
-5. Remove the `IncompletePage(..)` entry for that chart type in `chart_groups.py`.
-6. Update this `README.md` with the new chart type, its status, category, and API links.
+1. Add a `.py` file containing a code example of the chart type in the `pages/examples` folder, for instance, `area.py`. Take a look at existing examples.
+1. Create a new page for the chart type and add it to the relevant category `.py` file such as `correlation.py`, `deviation.py`, `distribution.py`, etc. Ensure you add the page to the list of `pages` at the end of the `.py` file.
+1. Remove the `IncompletePage(..)` entry for that chart type in `chart_groups.py`.
+1. Update this `README.md` with the new chart type, its status, category, and API links.
## How to run the example locally
1. Run the example with the command `hatch run example visual-vocabulary`.
-2. You should now be able to access the app locally via http://127.0.0.1:8050/.
+1. You should now be able to access the app locally via http://127.0.0.1:8051/.
diff --git a/vizro-core/examples/visual-vocabulary/assets/css/custom.css b/vizro-core/examples/visual-vocabulary/assets/css/custom.css
index ef2fce294..c69bbe58c 100644
--- a/vizro-core/examples/visual-vocabulary/assets/css/custom.css
+++ b/vizro-core/examples/visual-vocabulary/assets/css/custom.css
@@ -34,9 +34,7 @@ img[src*="#chart-icon"] {
position: relative;
}
-.code-clipboard-container .pycafe-link,
-.code-clipboard-container .pycafe-link:focus {
- line-height: unset;
+.code-clipboard-container .pycafe-link {
margin-bottom: 12px;
}
@@ -96,7 +94,7 @@ img[src*="#chart-icon"] {
background: var(--text-primary);
border-top-left-radius: 8px;
bottom: 0;
- color: var(--text-contrast-primary);
+ color: var(--text-primary-inverted);
display: flex;
font-size: 0.8rem;
font-weight: 500;
@@ -109,7 +107,7 @@ img[src*="#chart-icon"] {
.anchor-container:focus,
.anchor-container:hover {
background: var(--text-secondary);
- color: var(--text-contrast-primary);
+ color: var(--text-primary-inverted);
}
img#banner {
diff --git a/vizro-core/examples/visual-vocabulary/chart_groups.py b/vizro-core/examples/visual-vocabulary/chart_groups.py
index 2896306f8..527ae2d8b 100644
--- a/vizro-core/examples/visual-vocabulary/chart_groups.py
+++ b/vizro-core/examples/visual-vocabulary/chart_groups.py
@@ -81,7 +81,6 @@ class ChartGroup:
incomplete_pages=[
IncompletePage("Ordered bubble"),
IncompletePage("Slope"),
- IncompletePage("Lollipop"),
IncompletePage("Bump"),
],
icon="Stacked Bar Chart",
@@ -117,7 +116,6 @@ class ChartGroup:
pages=pages.magnitude.pages,
incomplete_pages=[
IncompletePage("Marimekko"),
- IncompletePage("Lollipop"),
IncompletePage("Pictogram"),
IncompletePage("Bullet"),
IncompletePage("Radial"),
@@ -138,7 +136,6 @@ class ChartGroup:
IncompletePage("Slope"),
IncompletePage("Fan"),
IncompletePage("Bubble timeline"),
- IncompletePage("Sparkline"),
],
icon="Timeline",
intro_text=time_intro_text,
diff --git a/vizro-core/examples/visual-vocabulary/custom_charts.py b/vizro-core/examples/visual-vocabulary/custom_charts.py
index 7e1f26948..6a7aae68b 100644
--- a/vizro-core/examples/visual-vocabulary/custom_charts.py
+++ b/vizro-core/examples/visual-vocabulary/custom_charts.py
@@ -290,12 +290,18 @@ def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure:
orientation = fig.data[0].orientation
x_or_y = "x" if orientation == "h" else "y"
- for trace_idx in range(len(fig.data) // 2):
+ for trace_idx in range(len(fig.data) // 2, len(fig.data)):
fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=trace_idx)
+ # Add ticksuffix and range limitations on both sids for correct interpretation of diverging stacked bar
+ # with percentage data
+ fig.update_layout({f"{x_or_y}axis": {"ticksuffix": "%"}})
fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]})
fig.update_layout(
- {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}}
+ {
+ f"{x_or_y}axis": {"domain": [0, 0.5], "range": [100, 0]},
+ f"{x_or_y}axis2": {"domain": [0.5, 1], "range": [0, 100]},
+ }
)
if orientation == "h":
@@ -304,3 +310,51 @@ def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure:
fig.add_hline(y=0, line_width=2, line_color="grey")
return fig
+
+
+@capture("graph")
+def lollipop(data_frame: pd.DataFrame, **kwargs):
+ """Creates a lollipop based on px.scatter.
+
+ A lollipop chart is a variation of a bar chart where each data point is represented by a line and a dot at the end
+ to mark the value.
+
+ Inspired by: https://towardsdatascience.com/lollipop-dumbbell-charts-with-plotly-696039d5f85
+
+ Args:
+ data_frame: DataFrame for the chart. Can be long form or wide form.
+ See https://plotly.com/python/wide-form/.
+ **kwargs: Keyword arguments to pass into px.scatter (e.g. x, y, labels).
+ See https://plotly.com/python-api-reference/generated/plotly.scatter.html.
+
+ Returns:
+ go.Figure: Lollipop chart.
+ """
+ # Plots the dots of the lollipop chart
+ fig = px.scatter(data_frame, **kwargs)
+
+ # Enables the orientation of the chart to be either horizontal or vertical
+ orientation = fig.data[0].orientation
+ x_or_y = "x" if orientation == "h" else "y"
+ y_or_x = "y" if orientation == "h" else "x"
+
+ # Plots the lines of the lollipop chart
+ for x_or_y_value, y_or_x_value in zip(fig.data[0][x_or_y], fig.data[0][y_or_x]):
+ fig.add_trace(go.Scatter({x_or_y: [0, x_or_y_value], y_or_x: [y_or_x_value, y_or_x_value], "mode": "lines"}))
+
+ # Styles the lollipop chart and makes it uni-colored
+ fig.update_traces(
+ marker_size=12,
+ line_width=3,
+ line_color=fig.layout.template.layout.colorway[0],
+ )
+
+ fig.update_layout(
+ {
+ "showlegend": False,
+ f"{x_or_y}axis_showgrid": True,
+ f"{y_or_x}axis_showgrid": False,
+ f"{x_or_y}axis_rangemode": "tozero",
+ },
+ )
+ return fig
diff --git a/vizro-core/examples/visual-vocabulary/pages/_factories.py b/vizro-core/examples/visual-vocabulary/pages/_factories.py
index 97b4615b5..9fa0deb77 100644
--- a/vizro-core/examples/visual-vocabulary/pages/_factories.py
+++ b/vizro-core/examples/visual-vocabulary/pages/_factories.py
@@ -7,7 +7,7 @@
import vizro.models as vm
from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file
-from pages.examples import butterfly, column_and_line, connected_scatter, waterfall
+from pages.examples import butterfly, column_and_line, connected_scatter, lollipop, waterfall
def butterfly_factory(group: str):
@@ -179,3 +179,48 @@ def waterfall_factory(group: str):
),
],
)
+
+
+def lollipop_factory(group: str):
+ """Reusable function to create the page content for the lollipop chart with a unique ID."""
+ return vm.Page(
+ id=f"{group}-lollipop",
+ path=f"{group}/lollipop",
+ title="Lollipop",
+ layout=vm.Layout(grid=PAGE_GRID),
+ components=[
+ vm.Card(
+ text="""
+
+ #### What is a lollipop chart?
+
+ A lollipop chart is a variation of a bar chart where each data point is represented by a line and a
+ dot at the end to mark the value. It functions like a bar chart but offers a cleaner visual,
+ especially useful when dealing with a large number of high values, to avoid the clutter of tall columns.
+ However, it can be less precise due to the difficulty in judging the exact center of the circle.
+
+
+
+ #### When should I use it?
+
+ Use a lollipop chart to compare values across categories, especially when dealing with many high values.
+ It highlights differences and trends clearly without the visual bulk of a bar chart. Ensure clarity by
+ limiting categories, using consistent scales, and clearly labeling axes. Consider alternatives if
+ precise value representation is crucial.
+ """
+ ),
+ vm.Graph(figure=lollipop.fig),
+ vm.Tabs(
+ tabs=[
+ vm.Container(
+ title="Vizro dashboard",
+ components=[make_code_clipboard_from_py_file("lollipop.py", mode="vizro")],
+ ),
+ vm.Container(
+ title="Plotly figure",
+ components=[make_code_clipboard_from_py_file("lollipop.py", mode="plotly")],
+ ),
+ ]
+ ),
+ ],
+ )
diff --git a/vizro-core/examples/visual-vocabulary/pages/examples/diverging_stacked_bar.py b/vizro-core/examples/visual-vocabulary/pages/examples/diverging_stacked_bar.py
index ae08c6629..e6ab63c0a 100644
--- a/vizro-core/examples/visual-vocabulary/pages/examples/diverging_stacked_bar.py
+++ b/vizro-core/examples/visual-vocabulary/pages/examples/diverging_stacked_bar.py
@@ -24,12 +24,16 @@ def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure:
orientation = fig.data[0].orientation
x_or_y = "x" if orientation == "h" else "y"
- for trace_idx in range(len(fig.data) // 2):
+ for trace_idx in range(len(fig.data) // 2, len(fig.data)):
fig.update_traces({f"{x_or_y}axis": f"{x_or_y}2"}, selector=trace_idx)
+ fig.update_layout({f"{x_or_y}axis": {"ticksuffix": "%"}})
fig.update_layout({f"{x_or_y}axis2": fig.layout[f"{x_or_y}axis"]})
fig.update_layout(
- {f"{x_or_y}axis": {"autorange": "reversed", "domain": [0, 0.5]}, f"{x_or_y}axis2": {"domain": [0.5, 1]}}
+ {
+ f"{x_or_y}axis": {"domain": [0, 0.5], "range": [100, 0]},
+ f"{x_or_y}axis2": {"domain": [0.5, 1], "range": [0, 100]},
+ }
)
if orientation == "h":
@@ -63,6 +67,6 @@ def diverging_stacked_bar(data_frame: pd.DataFrame, **kwargs) -> go.Figure:
data_frame=pastries,
x=["Strongly Disagree", "Disagree", "Agree", "Strongly Agree"],
y="pastry",
- labels={"value": "Response count", "variable": "Opinion"},
+ labels={"value": "", "variable": "", "pastry": ""},
title="I would recommend this pastry to my friends",
)
diff --git a/vizro-core/examples/visual-vocabulary/pages/examples/lollipop.py b/vizro-core/examples/visual-vocabulary/pages/examples/lollipop.py
new file mode 100644
index 000000000..9c483706a
--- /dev/null
+++ b/vizro-core/examples/visual-vocabulary/pages/examples/lollipop.py
@@ -0,0 +1,42 @@
+import pandas as pd
+import plotly.express as px
+import plotly.graph_objects as go
+from vizro.models.types import capture
+
+
+@capture("graph")
+def lollipop(data_frame: pd.DataFrame, **kwargs):
+ """Creates a lollipop chart using Plotly."""
+ fig = px.scatter(data_frame, **kwargs)
+
+ orientation = fig.data[0].orientation
+ x_or_y = "x" if orientation == "h" else "y"
+ y_or_x = "y" if orientation == "h" else "x"
+
+ for x_or_y_value, y_or_x_value in zip(fig.data[0][x_or_y], fig.data[0][y_or_x]):
+ fig.add_trace(go.Scatter({x_or_y: [0, x_or_y_value], y_or_x: [y_or_x_value, y_or_x_value], "mode": "lines"}))
+
+ fig.update_traces(
+ marker_size=12,
+ line_width=3,
+ line_color=fig.layout.template.layout.colorway[0],
+ )
+
+ fig.update_layout(
+ {
+ "showlegend": False,
+ f"{x_or_y}axis_showgrid": True,
+ f"{y_or_x}axis_showgrid": False,
+ f"{x_or_y}axis_rangemode": "tozero",
+ },
+ )
+ return fig
+
+
+gapminder = (
+ px.data.gapminder()
+ .query("year == 2007 and country.isin(['United States', 'Pakistan', 'India', 'China', 'Indonesia'])")
+ .sort_values("pop")
+)
+
+fig = lollipop(gapminder, y="country", x="pop")
diff --git a/vizro-core/examples/visual-vocabulary/pages/examples/sparkline.py b/vizro-core/examples/visual-vocabulary/pages/examples/sparkline.py
new file mode 100644
index 000000000..3d8b192d5
--- /dev/null
+++ b/vizro-core/examples/visual-vocabulary/pages/examples/sparkline.py
@@ -0,0 +1,16 @@
+import plotly.express as px
+from vizro.models.types import capture
+
+stocks = px.data.stocks()
+
+
+@capture("graph")
+def sparkline(data_frame, **kwargs):
+ fig = px.line(data_frame, **kwargs)
+ fig.update_xaxes(ticks="", showgrid=False, title="")
+ fig.update_yaxes(visible=False)
+ fig.update_layout(showlegend=False)
+ return fig
+
+
+fig = sparkline(stocks, x="date", y=["GOOG", "AMZN", "AAPL"], labels={"variable": "stock"}, facet_row="variable")
diff --git a/vizro-core/examples/visual-vocabulary/pages/magnitude.py b/vizro-core/examples/visual-vocabulary/pages/magnitude.py
index fc3b23337..983e190e8 100644
--- a/vizro-core/examples/visual-vocabulary/pages/magnitude.py
+++ b/vizro-core/examples/visual-vocabulary/pages/magnitude.py
@@ -2,6 +2,7 @@
import vizro.models as vm
+from pages._factories import lollipop_factory
from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file
from pages.examples import bar, magnitude_column, paired_bar, paired_column, parallel_coordinates, radar
@@ -238,4 +239,13 @@
],
)
-pages = [bar_page, column_page, paired_bar_page, paired_column_page, parallel_coordinates_page, radar_page]
+lollipop_page = lollipop_factory("magnitude")
+pages = [
+ bar_page,
+ column_page,
+ paired_bar_page,
+ paired_column_page,
+ parallel_coordinates_page,
+ radar_page,
+ lollipop_page,
+]
diff --git a/vizro-core/examples/visual-vocabulary/pages/ranking.py b/vizro-core/examples/visual-vocabulary/pages/ranking.py
index a788223d7..3ea7bdbe1 100644
--- a/vizro-core/examples/visual-vocabulary/pages/ranking.py
+++ b/vizro-core/examples/visual-vocabulary/pages/ranking.py
@@ -2,6 +2,7 @@
import vizro.models as vm
+from pages._factories import lollipop_factory
from pages._pages_utils import PAGE_GRID, make_code_clipboard_from_py_file
from pages.examples import ordered_bar, ordered_column
@@ -85,4 +86,6 @@
)
-pages = [ordered_bar_page, ordered_column_page]
+lollipop_page = lollipop_factory("deviation")
+
+pages = [ordered_bar_page, ordered_column_page, lollipop_page]
diff --git a/vizro-core/examples/visual-vocabulary/pages/time.py b/vizro-core/examples/visual-vocabulary/pages/time.py
index 6fda8d314..6143abcf7 100644
--- a/vizro-core/examples/visual-vocabulary/pages/time.py
+++ b/vizro-core/examples/visual-vocabulary/pages/time.py
@@ -7,7 +7,7 @@
PAGE_GRID,
make_code_clipboard_from_py_file,
)
-from pages.examples import area, gantt, heatmap, line, stepped_line, time_column
+from pages.examples import area, gantt, heatmap, line, sparkline, stepped_line, time_column
line_page = vm.Page(
title="Line",
@@ -212,19 +212,19 @@
#### What is a gantt chart?
A gantt chart is a type of bar chart that visualizes a project schedule.
-It shows the start and end dates of a project element, such as tasks, activities, or
-events, in a timeline format. Each element is represented by a bar whose length indicates
-its duration.
+ It shows the start and end dates of a project element, such as tasks, activities, or
+ events, in a timeline format. Each element is represented by a bar whose length indicates
+ its duration.
#### When should I use it?
Gantt charts are ideal for visualizing project timelines, tracking
-progress, and managing dependencies. They clearly display task start and end dates, making
-it easy to monitor project status and manage interdependencies. However, they can become
-complex if not regularly updated, especially for large projects.
- """
+ progress, and managing dependencies. They clearly display task start and end dates, making
+ it easy to monitor project status and manage interdependencies. However, they can become
+ complex if not regularly updated, especially for large projects.
+ """
),
vm.Graph(figure=gantt.fig),
vm.Tabs(
@@ -240,6 +240,46 @@
),
],
)
+
+
+sparkline_page = vm.Page(
+ title="Sparkline",
+ path="time/sparkline",
+ layout=vm.Layout(grid=PAGE_GRID),
+ components=[
+ vm.Card(
+ text="""
+ #### What is a sparkline chart?
+
+ A sparkline chart is a compact line or area chart that displays multiple time series over a continuous
+ period. Without visible axes or labels, they are ideal for embedding within text, tables, or dashboards,
+ highlighting relative movement rather than precise values for a quick visual summary of trends.
+
+
+
+ #### When should I use it?
+
+ Use sparkline charts to show trends for multiple time series sharing the same y-axis quantity over the
+ same x-axis time range. They emphasize relative movement rather than precise values. To keep them
+ effective, ensure simplicity by avoiding clutter. Use consistent scales and distinct colors for
+ different series. Remove labels and gridlines, limit annotations, and place sparklines near relevant
+ text or data.
+ """
+ ),
+ vm.Graph(figure=sparkline.fig),
+ vm.Tabs(
+ tabs=[
+ vm.Container(
+ title="Vizro dashboard", components=[make_code_clipboard_from_py_file("sparkline.py", mode="vizro")]
+ ),
+ vm.Container(
+ title="Plotly figure",
+ components=[make_code_clipboard_from_py_file("sparkline.py", mode="plotly")],
+ ),
+ ]
+ ),
+ ],
+)
pages = [
line_page,
column_page,
@@ -249,4 +289,5 @@
stepped_line_page,
heatmap_page,
gantt_page,
+ sparkline_page,
]
diff --git a/vizro-core/examples/visual-vocabulary/requirements.in b/vizro-core/examples/visual-vocabulary/requirements.in
index 701ad04d6..bc13bc273 100644
--- a/vizro-core/examples/visual-vocabulary/requirements.in
+++ b/vizro-core/examples/visual-vocabulary/requirements.in
@@ -3,5 +3,5 @@ autoflake==2.3.1
black==24.4.2
isort==5.13.2
plotly==5.24.1
-vizro==0.1.25
+vizro==0.1.28
gunicorn
diff --git a/vizro-core/examples/visual-vocabulary/requirements.txt b/vizro-core/examples/visual-vocabulary/requirements.txt
index 693b90a19..5981b1821 100644
--- a/vizro-core/examples/visual-vocabulary/requirements.txt
+++ b/vizro-core/examples/visual-vocabulary/requirements.txt
@@ -50,7 +50,9 @@ gunicorn==23.0.0
idna==3.10
# via requests
importlib-metadata==8.5.0
- # via dash
+ # via
+ # dash
+ # flask
isort==5.13.2
# via -r requirements.in
itsdangerous==2.2.0
@@ -65,7 +67,7 @@ mypy-extensions==1.0.0
# via black
nest-asyncio==1.6.0
# via dash
-numpy==2.1.2
+numpy==2.0.2
# via pandas
packaging==24.1
# via
@@ -105,8 +107,13 @@ six==1.16.0
# retrying
tenacity==9.0.0
# via plotly
+tomli==2.1.0
+ # via
+ # autoflake
+ # black
typing-extensions==4.12.2
# via
+ # black
# dash
# pydantic
# pydantic-core
@@ -114,7 +121,7 @@ tzdata==2024.2
# via pandas
urllib3==2.2.3
# via requests
-vizro==0.1.25
+vizro==0.1.28
# via -r requirements.in
werkzeug==3.0.6
# via
diff --git a/vizro-core/hatch.toml b/vizro-core/hatch.toml
index 0cecae8be..c18cc24fd 100644
--- a/vizro-core/hatch.toml
+++ b/vizro-core/hatch.toml
@@ -30,7 +30,10 @@ dependencies = [
"openpyxl",
"jupyter",
"pre-commit",
- "PyGithub"
+ "PyGithub",
+ "imutils",
+ "opencv-python",
+ "pyhamcrest"
]
installer = "uv"
@@ -55,7 +58,7 @@ schema-check = ["python schemas/generate.py --check"]
# fix this, but we don't actually use `hatch run test` anywhere right now.
# See comments added in https://github.com/mckinsey/vizro/pull/444.
test = "pytest tests --headless {args}"
-test-component-library = "pytest tests/component_library --headless {args}"
+test-e2e-component-library = "pytest tests/e2e/test_component_library.py --headless {args}"
test-integration = "pytest tests/integration --headless {args}"
test-js = "./tools/run_jest.sh {args}"
test-unit = "pytest tests/unit {args}"
@@ -111,7 +114,7 @@ VIZRO_LOG_LEVEL = "DEBUG"
[envs.lower-bounds]
extra-dependencies = [
"pydantic==1.10.16",
- "dash==2.17.1",
+ "dash==2.18.0",
"plotly==5.12.0",
"pandas==2.0.0",
"numpy==1.23.0" # Need numpy<2 to work with pandas==2.0.0. See https://stackoverflow.com/questions/78634235/.
@@ -119,14 +122,6 @@ extra-dependencies = [
features = ["kedro"]
python = "3.9"
-[envs.tests]
-extra-dependencies = [
- "imutils",
- "opencv-python",
- "pyhamcrest"
-]
-python = "3.12"
-
[publish.index]
disable = true
diff --git a/vizro-core/mkdocs.yml b/vizro-core/mkdocs.yml
index bede305e6..d09520f77 100644
--- a/vizro-core/mkdocs.yml
+++ b/vizro-core/mkdocs.yml
@@ -56,7 +56,7 @@ nav:
- Documentation style: pages/explanation/documentation-style-guide.md
- Authors: pages/explanation/authors.md
- Examples:
- - Vizro gallery: https://vizro.mckinsey.com/
+ - Gallery: https://vizro.mckinsey.com/
- Vizro-AI:
- Vizro-AI: https://vizro.readthedocs.io/projects/vizro-ai/
@@ -112,7 +112,7 @@ markdown_extensions:
kwds:
type: vizro
requirements: |
- vizro==0.1.26
+ vizro==0.1.29
- pymdownx.tabbed:
alternate_style: true
- pymdownx.mark
@@ -144,6 +144,10 @@ plugins:
- git-revision-date-localized:
enable_creation_date: false
+extra:
+ meta:
+ - name: google-site-verification
+ content: "CYb3cxosCgsN2QDQVaSGQpMQCesqpsGQ3oTM02NtvkY"
extra_css:
- stylesheets/extra.css
diff --git a/vizro-core/pyproject.toml b/vizro-core/pyproject.toml
index a1992ddc8..1bf2b9577 100644
--- a/vizro-core/pyproject.toml
+++ b/vizro-core/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.13"
]
dependencies = [
- "dash>=2.17.1", # 2.17.1 needed for no_output fix in clientside_callback
+ "dash>=2.18.0,<3", # 2.18.0 needed as the 'id' attribute is exposed for dcc.Loading
"dash_bootstrap_components",
"dash-ag-grid>=31.0.0",
"pandas>=2",
@@ -79,7 +79,9 @@ filterwarnings = [
# Ignore warning when using the fig.layout.title inside examples:
"ignore:Using the `title` argument in your Plotly chart function may cause misalignment:UserWarning",
# Ignore warning for Pydantic v1 API and Python 3.13:
- "ignore:Failing to pass a value to the 'type_params' parameter of 'typing.ForwardRef._evaluate' is deprecated:DeprecationWarning"
+ "ignore:Failing to pass a value to the 'type_params' parameter of 'typing.ForwardRef._evaluate' is deprecated:DeprecationWarning",
+ # Ignore deprecation warning until this is solved: https://github.com/plotly/dash/issues/2590:
+ "ignore:HTTPResponse.getheader():DeprecationWarning"
]
norecursedirs = ["tests/tests_utils", "tests/js"]
pythonpath = ["tests/tests_utils"]
diff --git a/vizro-core/schemas/0.1.26.json b/vizro-core/schemas/0.1.29.json
similarity index 99%
rename from vizro-core/schemas/0.1.26.json
rename to vizro-core/schemas/0.1.29.json
index d5002ea1f..d69755927 100644
--- a/vizro-core/schemas/0.1.26.json
+++ b/vizro-core/schemas/0.1.29.json
@@ -141,6 +141,12 @@
"default": "Click me!",
"type": "string"
},
+ "href": {
+ "title": "Href",
+ "description": "URL (relative or absolute) to navigate to.",
+ "default": "",
+ "type": "string"
+ },
"actions": {
"title": "Actions",
"default": [],
diff --git a/vizro-core/schemas/0.1.27.dev0.json b/vizro-core/schemas/0.1.30.dev0.json
similarity index 99%
rename from vizro-core/schemas/0.1.27.dev0.json
rename to vizro-core/schemas/0.1.30.dev0.json
index d5002ea1f..d69755927 100644
--- a/vizro-core/schemas/0.1.27.dev0.json
+++ b/vizro-core/schemas/0.1.30.dev0.json
@@ -141,6 +141,12 @@
"default": "Click me!",
"type": "string"
},
+ "href": {
+ "title": "Href",
+ "description": "URL (relative or absolute) to navigate to.",
+ "default": "",
+ "type": "string"
+ },
"actions": {
"title": "Actions",
"default": [],
diff --git a/vizro-core/src/vizro/__init__.py b/vizro-core/src/vizro/__init__.py
index e10f21fb0..6a77ff59c 100644
--- a/vizro-core/src/vizro/__init__.py
+++ b/vizro-core/src/vizro/__init__.py
@@ -14,7 +14,7 @@
__all__ = ["Vizro"]
-__version__ = "0.1.27.dev0"
+__version__ = "0.1.30.dev0"
# For the below _css_dist and _js_dist to be used by Dash, they must be retrieved by dash.resources.Css.get_all_css().
diff --git a/vizro-core/src/vizro/_vizro.py b/vizro-core/src/vizro/_vizro.py
index 55d30a5fe..f648d053f 100644
--- a/vizro-core/src/vizro/_vizro.py
+++ b/vizro-core/src/vizro/_vizro.py
@@ -5,7 +5,7 @@
from collections.abc import Iterable
from contextlib import suppress
from pathlib import Path, PurePosixPath
-from typing import TYPE_CHECKING, TypedDict
+from typing import TYPE_CHECKING, TypedDict, cast
import dash
import plotly.io as pio
@@ -15,7 +15,7 @@
import vizro
from vizro._constants import VIZRO_ASSETS_PATH
from vizro.managers import data_manager, model_manager
-from vizro.models import Dashboard
+from vizro.models import Dashboard, Filter
logger = logging.getLogger(__name__)
@@ -144,9 +144,16 @@ def _pre_build():
# changes size.
# Any models that are created during the pre-build process *will not* themselves have pre_build run on them.
# In future may add a second pre_build loop after the first one.
+
+ for filter in cast(Iterable[Filter], model_manager._get_models(Filter)):
+ # Run pre_build on all filters first, then on all other models. This handles dependency between Filter
+ # and Page pre_build and ensures that filters are pre-built before the Page objects that use them.
+ # This is important because the Page pre_build method checks whether filters are dynamic or not, which is
+ # defined in the filter's pre_build method.
+ filter.pre_build()
for model_id in set(model_manager):
model = model_manager[model_id]
- if hasattr(model, "pre_build"):
+ if hasattr(model, "pre_build") and not isinstance(model, Filter):
model.pre_build()
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]:
diff --git a/vizro-core/src/vizro/actions/_action_loop/_action_loop.py b/vizro-core/src/vizro/actions/_action_loop/_action_loop.py
index d9caac0ff..2d8edefa9 100644
--- a/vizro-core/src/vizro/actions/_action_loop/_action_loop.py
+++ b/vizro-core/src/vizro/actions/_action_loop/_action_loop.py
@@ -1,10 +1,14 @@
"""The action loop creates all the required action callbacks and its components."""
+from collections.abc import Iterable
+from typing import cast
+
from dash import html
-from vizro.actions._action_loop._action_loop_utils import _get_actions_on_registered_pages
from vizro.actions._action_loop._build_action_loop_callbacks import _build_action_loop_callbacks
from vizro.actions._action_loop._get_action_loop_components import _get_action_loop_components
+from vizro.managers import model_manager
+from vizro.models import Action
class ActionLoop:
@@ -37,5 +41,8 @@ def _build_actions_models():
List of required components for each `Action` in the `Dashboard` e.g. list[dcc.Download]
"""
- actions = _get_actions_on_registered_pages()
- return html.Div([action.build() for action in actions], id="app_action_models_components_div", hidden=True)
+ return html.Div(
+ [action.build() for action in cast(Iterable[Action], model_manager._get_models(Action))],
+ id="app_action_models_components_div",
+ hidden=True,
+ )
diff --git a/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py b/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py
deleted file mode 100644
index d640f24bb..000000000
--- a/vizro-core/src/vizro/actions/_action_loop/_action_loop_utils.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""Contains utilities to extract the Action and ActionsChain models from registered pages only."""
-
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-import dash
-
-from vizro.managers import model_manager
-from vizro.managers._model_manager import ModelID
-
-if TYPE_CHECKING:
- from vizro.models import Action, Page
- from vizro.models._action._actions_chain import ActionsChain
-
-
-def _get_actions_chains_on_all_pages() -> list[ActionsChain]:
- """Gets list of ActionsChain models for registered pages."""
- actions_chains: list[ActionsChain] = []
- # TODO: once dash.page_registry matches up with model_manager, change this to use purely model_manager.
- # Making the change now leads to problems since there can be Action models defined that aren't used in the
- # dashboard.
- # See https://github.com/mckinsey/vizro/pull/366.
- for registered_page in dash.page_registry.values():
- try:
- page: Page = model_manager[registered_page["module"]]
- except KeyError:
- continue
- actions_chains.extend(model_manager._get_page_actions_chains(page_id=ModelID(str(page.id))))
- return actions_chains
-
-
-def _get_actions_on_registered_pages() -> list[Action]:
- """Gets list of Action models for registered pages."""
- return [action for action_chain in _get_actions_chains_on_all_pages() for action in action_chain.actions]
diff --git a/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py b/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py
index bc76a146d..439c443e1 100644
--- a/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py
+++ b/vizro-core/src/vizro/actions/_action_loop/_build_action_loop_callbacks.py
@@ -4,20 +4,20 @@
from dash import ClientsideFunction, Input, Output, State, clientside_callback
-from vizro.actions._action_loop._action_loop_utils import (
- _get_actions_chains_on_all_pages,
- _get_actions_on_registered_pages,
-)
from vizro.managers import model_manager
from vizro.managers._model_manager import ModelID
+from vizro.models import Action
+from vizro.models._action._actions_chain import ActionsChain
logger = logging.getLogger(__name__)
def _build_action_loop_callbacks() -> None:
"""Creates all required dash callbacks for the action loop."""
- actions_chains = _get_actions_chains_on_all_pages()
- actions = _get_actions_on_registered_pages()
+ # actions_chain and actions are not iterated over multiple times so conversion to list is not technically needed,
+ # but it prevents future bugs and matches _get_action_loop_components.
+ actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
+ actions: list[Action] = list(model_manager._get_models(Action))
if not actions_chains:
return
diff --git a/vizro-core/src/vizro/actions/_action_loop/_get_action_loop_components.py b/vizro-core/src/vizro/actions/_action_loop/_get_action_loop_components.py
index 7d34c2a4a..2d18c18df 100644
--- a/vizro-core/src/vizro/actions/_action_loop/_get_action_loop_components.py
+++ b/vizro-core/src/vizro/actions/_action_loop/_get_action_loop_components.py
@@ -2,10 +2,9 @@
from dash import dcc, html
-from vizro.actions._action_loop._action_loop_utils import (
- _get_actions_chains_on_all_pages,
- _get_actions_on_registered_pages,
-)
+from vizro.managers import model_manager
+from vizro.models import Action
+from vizro.models._action._actions_chain import ActionsChain
def _get_action_loop_components() -> html.Div:
@@ -15,8 +14,9 @@ def _get_action_loop_components() -> html.Div:
List of dcc or html components.
"""
- actions_chains = _get_actions_chains_on_all_pages()
- actions = _get_actions_on_registered_pages()
+ # actions_chain and actions are iterated over multiple times so must be realized into a list.
+ actions_chains: list[ActionsChain] = list(model_manager._get_models(ActionsChain))
+ actions: list[Action] = list(model_manager._get_models(Action))
if not actions_chains:
return html.Div(id="action_loop_components_div")
diff --git a/vizro-core/src/vizro/actions/_actions_utils.py b/vizro-core/src/vizro/actions/_actions_utils.py
index 484d41ed4..1873b6620 100644
--- a/vizro-core/src/vizro/actions/_actions_utils.py
+++ b/vizro-core/src/vizro/actions/_actions_utils.py
@@ -2,8 +2,9 @@
from __future__ import annotations
+from collections.abc import Iterable
from copy import deepcopy
-from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union
+from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict, Union, cast
import pandas as pd
@@ -48,18 +49,18 @@ def _get_component_actions(component) -> list[Action]:
def _apply_filter_controls(
- data_frame: pd.DataFrame, ctds_filters: list[CallbackTriggerDict], target: ModelID
+ data_frame: pd.DataFrame, ctds_filter: list[CallbackTriggerDict], target: ModelID
) -> pd.DataFrame:
"""Applies filters from a vm.Filter model in the controls.
Args:
data_frame: unfiltered DataFrame.
- ctds_filters: list of CallbackTriggerDict for filters.
+ ctds_filter: list of CallbackTriggerDict for filters.
target: id of targeted Figure.
Returns: filtered DataFrame.
"""
- for ctd in ctds_filters:
+ for ctd in ctds_filter:
selector_value = ctd["value"]
selector_value = selector_value if isinstance(selector_value, list) else [selector_value]
selector_actions = _get_component_actions(model_manager[ctd["id"]])
@@ -80,15 +81,12 @@ def _apply_filter_controls(
return data_frame
-def _get_parent_vizro_model(_underlying_callable_object_id: str) -> VizroBaseModel:
+def _get_parent_model(_underlying_callable_object_id: str) -> VizroBaseModel:
from vizro.models import VizroBaseModel
- for _, vizro_base_model in model_manager._items_with_type(VizroBaseModel):
- if (
- hasattr(vizro_base_model, "_input_component_id")
- and vizro_base_model._input_component_id == _underlying_callable_object_id
- ):
- return vizro_base_model
+ for model in cast(Iterable[VizroBaseModel], model_manager._get_models()):
+ if hasattr(model, "_input_component_id") and model._input_component_id == _underlying_callable_object_id:
+ return model
raise KeyError(
f"No parent Vizro model found for underlying callable object with id: {_underlying_callable_object_id}."
)
@@ -164,12 +162,12 @@ def _update_nested_figure_properties(
def _get_parametrized_config(
- ctd_parameters: list[CallbackTriggerDict], target: ModelID, data_frame: bool
+ ctds_parameter: list[CallbackTriggerDict], target: ModelID, data_frame: bool
) -> dict[str, Any]:
"""Convert parameters into a keyword-argument dictionary.
Args:
- ctd_parameters: list of CallbackTriggerDicts for vm.Parameter.
+ ctds_parameter: list of CallbackTriggerDicts for vm.Parameter.
target: id of targeted figure.
data_frame: whether to return only DataFrame parameters starting "data_frame." or only non-DataFrame parameters.
@@ -187,7 +185,7 @@ def _get_parametrized_config(
config = deepcopy(model_manager[target].figure._arguments)
del config["data_frame"]
- for ctd in ctd_parameters:
+ for ctd in ctds_parameter:
# TODO: needs to be refactored so that it is independent of implementation details
parameter_value = ctd["value"]
@@ -223,7 +221,7 @@ def _apply_filters(
# Takes in just one target, so dataframe is filtered repeatedly for every target that uses it.
# Potentially this could be de-duplicated but it's not so important since filtering is a relatively fast
# operation (compared to data loading).
- filtered_data = _apply_filter_controls(data_frame=data, ctds_filters=ctds_filter, target=target)
+ filtered_data = _apply_filter_controls(data_frame=data, ctds_filter=ctds_filter, target=target)
filtered_data = _apply_filter_interaction(
data_frame=filtered_data, ctds_filter_interaction=ctds_filter_interaction, target=target
)
@@ -231,17 +229,17 @@ def _apply_filters(
def _get_unfiltered_data(
- ctds_parameters: list[CallbackTriggerDict], targets: list[ModelID]
+ ctds_parameter: list[CallbackTriggerDict], targets: list[ModelID]
) -> dict[ModelID, pd.DataFrame]:
# Takes in multiple targets to ensure that data can be loaded efficiently using _multi_load and not repeated for
# every single target.
- # Getting unfiltered data requires data frame parameters. We pass in all ctd_parameters and then find the
+ # Getting unfiltered data requires data frame parameters. We pass in all ctds_parameter and then find the
# data_frame ones by passing data_frame=True in the call to _get_paramaterized_config. Static data is also
# handled here and will just have empty dictionary for its kwargs.
multi_data_source_name_load_kwargs: list[tuple[DataSourceName, dict[str, Any]]] = []
for target in targets:
dynamic_data_load_params = _get_parametrized_config(
- ctd_parameters=ctds_parameters, target=target, data_frame=True
+ ctds_parameter=ctds_parameter, target=target, data_frame=True
)
data_source_name = model_manager[target]["data_frame"]
multi_data_source_name_load_kwargs.append((data_source_name, dynamic_data_load_params["data_frame"]))
@@ -252,25 +250,45 @@ def _get_unfiltered_data(
def _get_modified_page_figures(
ctds_filter: list[CallbackTriggerDict],
ctds_filter_interaction: list[dict[str, CallbackTriggerDict]],
- ctds_parameters: list[CallbackTriggerDict],
+ ctds_parameter: list[CallbackTriggerDict],
targets: list[ModelID],
) -> dict[ModelID, Any]:
+ from vizro.models import Filter
+
outputs: dict[ModelID, Any] = {}
+ control_targets = []
+ figure_targets = []
+ for target in targets:
+ if isinstance(model_manager[target], Filter):
+ control_targets.append(target)
+ else:
+ figure_targets.append(target)
+
+ # TODO-NEXT: Add fetching unfiltered data for the Filter.targets as well, once dynamic filters become "targetable"
+ # from other actions too. For example, in future, if Parameter is targeting only a single Filter.
+ # Currently, it only works for the on_page_load because Filter.targets are indeed the part of the actions' targets.
+ # More about the limitation: https://github.com/mckinsey/vizro/pull/879/files#r1863535516
+ target_to_data_frame = _get_unfiltered_data(ctds_parameter=ctds_parameter, targets=figure_targets)
+
# TODO: the structure here would be nicer if we could get just the ctds for a single target at one time,
# so you could do apply_filters on a target a pass only the ctds relevant for that target.
# Consider restructuring ctds to a more convenient form to make this possible.
-
- for target, unfiltered_data in _get_unfiltered_data(ctds_parameters, targets).items():
+ for target, unfiltered_data in target_to_data_frame.items():
filtered_data = _apply_filters(unfiltered_data, ctds_filter, ctds_filter_interaction, target)
outputs[target] = model_manager[target](
data_frame=filtered_data,
- **_get_parametrized_config(ctd_parameters=ctds_parameters, target=target, data_frame=False),
+ **_get_parametrized_config(ctds_parameter=ctds_parameter, target=target, data_frame=False),
)
- # TODO NEXT: will need to pass unfiltered_data into Filter.__call__.
- # This dictionary is filtered for correct targets already selected in Filter.__call__ or that could be done here
- # instead.
- # {target: data_frame for target, data_frame in unfiltered_data.items() if target in self.targets}
+ for target in control_targets:
+ ctd_filter = [item for item in ctds_filter if item["id"] == model_manager[target].selector.id]
+
+ # This only covers the case of cross-page actions when Filter in an output, but is not an input of the action.
+ current_value = ctd_filter[0]["value"] if ctd_filter else None
+
+ # target_to_data_frame contains all targets, including some which might not be relevant for the filter in
+ # question. We filter to use just the relevant targets in Filter.__call__.
+ outputs[target] = model_manager[target](target_to_data_frame=target_to_data_frame, current_value=current_value)
return outputs
diff --git a/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py b/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py
index 4bf82991c..ba18e4fa5 100644
--- a/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py
+++ b/vizro-core/src/vizro/actions/_callback_mapping/_callback_mapping_utils.py
@@ -1,13 +1,15 @@
"""Contains utilities to create the action_callback_mapping."""
-from typing import Any, Callable, Union
+from collections.abc import Iterable
+from typing import Any, Callable, Union, cast
from dash import Output, State, dcc
from vizro.actions import _parameter, filter_interaction
from vizro.managers import model_manager
-from vizro.managers._model_manager import ModelID
-from vizro.models import Action, Page
+from vizro.managers._model_manager import FIGURE_MODELS, ModelID
+from vizro.models import Action, Page, VizroBaseModel
+from vizro.models._action._actions_chain import ActionsChain
from vizro.models._controls import Filter, Parameter
from vizro.models.types import ControlType
@@ -15,13 +17,11 @@
# This function can also be reused for all other inputs (filters, parameters).
# Potentially this could be a way to reconcile predefined with custom actions,
# and make that predefined actions see and add into account custom actions.
-def _get_matching_actions_by_function(
- page_id: ModelID, action_function: Callable[[Any], dict[str, Any]]
-) -> list[Action]:
+def _get_matching_actions_by_function(page: Page, action_function: Callable[[Any], dict[str, Any]]) -> list[Action]:
"""Gets list of `Actions` on triggered `Page` that match the provided `action_function`."""
return [
action
- for actions_chain in model_manager._get_page_actions_chains(page_id=page_id)
+ for actions_chain in cast(Iterable[ActionsChain], model_manager._get_models(ActionsChain, page))
for action in actions_chain.actions
if action.function._function == action_function
]
@@ -32,21 +32,27 @@ def _get_inputs_of_controls(page: Page, control_type: ControlType) -> list[State
"""Gets list of `States` for selected `control_type` of triggered `Page`."""
return [
State(component_id=control.selector.id, component_property=control.selector._input_property)
- for control in page.controls
- if isinstance(control, control_type)
+ for control in cast(Iterable[ControlType], model_manager._get_models(control_type, page))
]
+def _get_action_trigger(action: Action) -> VizroBaseModel: # type: ignore[return]
+ """Gets the model that triggers the action with "action_id"."""
+ from vizro.models._action._actions_chain import ActionsChain
+
+ for actions_chain in cast(Iterable[ActionsChain], model_manager._get_models(ActionsChain)):
+ if action in actions_chain.actions:
+ return model_manager[ModelID(str(actions_chain.trigger.component_id))]
+
+
def _get_inputs_of_figure_interactions(
page: Page, action_function: Callable[[Any], dict[str, Any]]
) -> list[dict[str, State]]:
"""Gets list of `States` for selected chart interaction `action_function` of triggered `Page`."""
- figure_interactions_on_page = _get_matching_actions_by_function(
- page_id=ModelID(str(page.id)), action_function=action_function
- )
+ figure_interactions_on_page = _get_matching_actions_by_function(page=page, action_function=action_function)
inputs = []
for action in figure_interactions_on_page:
- triggered_model = model_manager._get_action_trigger(action_id=ModelID(str(action.id)))
+ triggered_model = _get_action_trigger(action)
required_attributes = ["_filter_interaction_input", "_filter_interaction"]
for attribute in required_attributes:
if not hasattr(triggered_model, attribute):
@@ -60,9 +66,9 @@ def _get_inputs_of_figure_interactions(
# TODO: Refactor this and util functions once we implement "_get_input_property" method in VizroBaseModel models
-def _get_action_callback_inputs(action_id: ModelID) -> dict[str, list[Union[State, dict[str, State]]]]:
+def _get_action_callback_inputs(action: Action) -> dict[str, list[Union[State, dict[str, State]]]]:
"""Creates mapping of pre-defined action names and a list of `States`."""
- page: Page = model_manager[model_manager._get_model_page_id(model_id=action_id)]
+ page = model_manager._get_model_page(action)
action_input_mapping = {
"filters": _get_inputs_of_controls(page=page, control_type=Filter),
@@ -76,9 +82,9 @@ def _get_action_callback_inputs(action_id: ModelID) -> dict[str, list[Union[Stat
# CALLBACK OUTPUTS --------------
-def _get_action_callback_outputs(action_id: ModelID) -> dict[str, Output]:
+def _get_action_callback_outputs(action: Action) -> dict[str, Output]:
"""Creates mapping of target names and their `Output`."""
- action_function = model_manager[action_id].function._function
+ action_function = action.function._function
# The right solution for mypy here is to not e.g. define new attributes on the base but instead to get mypy to
# recognize that model_manager[action_id] is of type Action and hence has the function attribute.
@@ -86,7 +92,7 @@ def _get_action_callback_outputs(action_id: ModelID) -> dict[str, Output]:
# If not then we can do the cast to Action at the point of consumption here to avoid needing mypy ignores.
try:
- targets = model_manager[action_id].function["targets"]
+ targets = action.function["targets"]
except KeyError:
targets = []
@@ -103,23 +109,23 @@ def _get_action_callback_outputs(action_id: ModelID) -> dict[str, Output]:
}
-def _get_export_data_callback_outputs(action_id: ModelID) -> dict[str, Output]:
+def _get_export_data_callback_outputs(action: Action) -> dict[str, Output]:
"""Gets mapping of relevant output target name and `Outputs` for `export_data` action."""
- action = model_manager[action_id]
-
try:
targets = action.function["targets"]
except KeyError:
targets = None
- if not targets:
- targets = model_manager._get_page_model_ids_with_figure(
- page_id=model_manager._get_model_page_id(model_id=action_id)
+ targets = targets or [
+ model.id
+ for model in cast(
+ Iterable[VizroBaseModel], model_manager._get_models(FIGURE_MODELS, model_manager._get_model_page(action))
)
+ ]
return {
f"download_dataframe_{target}": Output(
- component_id={"type": "download_dataframe", "action_id": action_id, "target_id": target},
+ component_id={"type": "download_dataframe", "action_id": action.id, "target_id": target},
component_property="data",
)
for target in targets
@@ -127,21 +133,21 @@ def _get_export_data_callback_outputs(action_id: ModelID) -> dict[str, Output]:
# CALLBACK COMPONENTS --------------
-def _get_export_data_callback_components(action_id: ModelID) -> list[dcc.Download]:
+def _get_export_data_callback_components(action: Action) -> list[dcc.Download]:
"""Creates dcc.Downloads for target components of the `export_data` action."""
- action = model_manager[action_id]
-
try:
targets = action.function["targets"]
except KeyError:
targets = None
- if not targets:
- targets = model_manager._get_page_model_ids_with_figure(
- page_id=model_manager._get_model_page_id(model_id=action_id)
+ targets = targets or [
+ model.id
+ for model in cast(
+ Iterable[VizroBaseModel], model_manager._get_models(FIGURE_MODELS, model_manager._get_model_page(action))
)
+ ]
return [
- dcc.Download(id={"type": "download_dataframe", "action_id": action_id, "target_id": target})
+ dcc.Download(id={"type": "download_dataframe", "action_id": action.id, "target_id": target})
for target in targets
]
diff --git a/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py b/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py
index 10841e18b..5b797835c 100644
--- a/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py
+++ b/vizro-core/src/vizro/actions/_callback_mapping/_get_action_callback_mapping.py
@@ -15,15 +15,12 @@
from vizro.actions._filter_action import _filter
from vizro.actions._on_page_load_action import _on_page_load
from vizro.actions._parameter_action import _parameter
-from vizro.managers import model_manager
-from vizro.managers._model_manager import ModelID
+from vizro.models import Action
-def _get_action_callback_mapping(
- action_id: ModelID, argument: str
-) -> Union[list[dcc.Download], dict[str, DashDependency]]:
+def _get_action_callback_mapping(action: Action, argument: str) -> Union[list[dcc.Download], dict[str, DashDependency]]:
"""Creates mapping of action name and required callback input/output."""
- action_function = model_manager[action_id].function._function
+ action_function = action.function._function
action_callback_mapping: dict[str, Any] = {
export_data.__wrapped__: {
@@ -50,4 +47,4 @@ def _get_action_callback_mapping(
}
action_call = action_callback_mapping.get(action_function, {}).get(argument)
default_value: Union[list[dcc.Download], dict[str, DashDependency]] = [] if argument == "components" else {}
- return default_value if not action_call else action_call(action_id=action_id)
+ return default_value if not action_call else action_call(action=action)
diff --git a/vizro-core/src/vizro/actions/_filter_action.py b/vizro-core/src/vizro/actions/_filter_action.py
index f3ec21b37..d50f0125c 100644
--- a/vizro-core/src/vizro/actions/_filter_action.py
+++ b/vizro-core/src/vizro/actions/_filter_action.py
@@ -32,6 +32,6 @@ def _filter(
return _get_modified_page_figures(
ctds_filter=ctx.args_grouping["external"]["filters"],
ctds_filter_interaction=ctx.args_grouping["external"]["filter_interaction"],
- ctds_parameters=ctx.args_grouping["external"]["parameters"],
+ ctds_parameter=ctx.args_grouping["external"]["parameters"],
targets=targets,
)
diff --git a/vizro-core/src/vizro/actions/_on_page_load_action.py b/vizro-core/src/vizro/actions/_on_page_load_action.py
index 306ed9b5e..c6611fbd5 100644
--- a/vizro-core/src/vizro/actions/_on_page_load_action.py
+++ b/vizro-core/src/vizro/actions/_on_page_load_action.py
@@ -25,6 +25,6 @@ def _on_page_load(targets: list[ModelID], **inputs: dict[str, Any]) -> dict[Mode
return _get_modified_page_figures(
ctds_filter=ctx.args_grouping["external"]["filters"],
ctds_filter_interaction=ctx.args_grouping["external"]["filter_interaction"],
- ctds_parameters=ctx.args_grouping["external"]["parameters"],
+ ctds_parameter=ctx.args_grouping["external"]["parameters"],
targets=targets,
)
diff --git a/vizro-core/src/vizro/actions/_parameter_action.py b/vizro-core/src/vizro/actions/_parameter_action.py
index 6284481ec..bfc58014f 100644
--- a/vizro-core/src/vizro/actions/_parameter_action.py
+++ b/vizro-core/src/vizro/actions/_parameter_action.py
@@ -27,6 +27,6 @@ def _parameter(targets: list[str], **inputs: dict[str, Any]) -> dict[ModelID, An
return _get_modified_page_figures(
ctds_filter=ctx.args_grouping["external"]["filters"],
ctds_filter_interaction=ctx.args_grouping["external"]["filter_interaction"],
- ctds_parameters=ctx.args_grouping["external"]["parameters"],
+ ctds_parameter=ctx.args_grouping["external"]["parameters"],
targets=target_ids,
)
diff --git a/vizro-core/src/vizro/actions/filter_interaction_action.py b/vizro-core/src/vizro/actions/filter_interaction_action.py
index bc6659ab9..9618d265f 100644
--- a/vizro-core/src/vizro/actions/filter_interaction_action.py
+++ b/vizro-core/src/vizro/actions/filter_interaction_action.py
@@ -31,6 +31,6 @@ def filter_interaction(targets: Optional[list[ModelID]] = None, **inputs: dict[s
return _get_modified_page_figures(
ctds_filter=ctx.args_grouping["external"]["filters"],
ctds_filter_interaction=ctx.args_grouping["external"]["filter_interaction"],
- ctds_parameters=ctx.args_grouping["external"]["parameters"],
+ ctds_parameter=ctx.args_grouping["external"]["parameters"],
targets=targets or [],
)
diff --git a/vizro-core/src/vizro/managers/_model_manager.py b/vizro-core/src/vizro/managers/_model_manager.py
index 14081681a..fe19a1e11 100644
--- a/vizro-core/src/vizro/managers/_model_manager.py
+++ b/vizro-core/src/vizro/managers/_model_manager.py
@@ -4,14 +4,14 @@
import random
import uuid
-from collections.abc import Generator
-from typing import TYPE_CHECKING, NewType, Optional, TypeVar, cast
+from collections.abc import Generator, Iterable
+from typing import TYPE_CHECKING, NewType, Optional, TypeVar, Union, cast
from vizro.managers._managers_utils import _state_modifier
if TYPE_CHECKING:
- from vizro.models import VizroBaseModel
- from vizro.models._action._actions_chain import ActionsChain
+ from vizro.models import Page, VizroBaseModel
+
# As done for Dash components in dash.development.base_component, fixing the random seed is required to make sure that
# the randomly generated model ID for the same model matches up across workers when running gunicorn without --preload.
@@ -21,6 +21,13 @@
Model = TypeVar("Model", bound="VizroBaseModel")
+# Sentinel object for models that are reactive to controls. This can't be done directly by defining
+# FIGURE_MODELS = (Graph, ...) due to circular imports. Done as class for mypy.
+# https://stackoverflow.com/questions/69239403/type-hinting-parameters-with-a-sentinel-value-as-the-default
+class FIGURE_MODELS:
+ pass
+
+
class DuplicateIDError(ValueError):
"""Useful for providing a more explicit error message when a model has id set automatically, e.g. Page."""
@@ -50,90 +57,71 @@ def __iter__(self) -> Generator[ModelID, None, None]:
Note this yields model IDs rather key/value pairs to match the interface for a dictionary.
"""
+ # TODO: should this yield models rather than model IDs? Should model_manager be more like set with a special
+ # lookup by model ID or more like dictionary?
yield from self.__models
- # TODO: Consider adding an option to iterate only through specific page - "in_page_with_id=None"
- def _items_with_type(self, model_type: type[Model]) -> Generator[tuple[ModelID, Model], None, None]:
- """Iterates through all models of type `model_type` (including subclasses)."""
- for model_id in self:
- if isinstance(self[model_id], model_type):
- yield model_id, cast(Model, self[model_id])
-
- # TODO: Consider returning with yield
- # TODO: Make collection of model ids (throughout this file) to be set[ModelID].
- def _get_model_children(self, model_id: ModelID, all_model_ids: Optional[list[ModelID]] = None) -> list[ModelID]:
- if all_model_ids is None:
- all_model_ids = []
-
- all_model_ids.append(model_id)
- model = self[model_id]
- if hasattr(model, "components"):
- for child_model in model.components:
- self._get_model_children(child_model.id, all_model_ids)
- if hasattr(model, "tabs"):
- for child_model in model.tabs:
- self._get_model_children(child_model.id, all_model_ids)
- return all_model_ids
-
- # TODO: Consider moving this method in the Dashboard model or some other util file
- def _get_model_page_id(self, model_id: ModelID) -> ModelID: # type: ignore[return]
- """Gets the id of the page containing the model with "model_id"."""
+ def _get_models(
+ self,
+ model_type: Optional[Union[type[Model], tuple[type[Model], ...], type[FIGURE_MODELS]]] = None,
+ page: Optional[Page] = None,
+ ) -> Generator[Model, None, None]:
+ """Iterates through all models of type `model_type` (including subclasses).
+
+ If `model_type` not given then look at all models. If `page` specified then only give models from that page.
+ """
+ import vizro.models as vm
+
+ if model_type is FIGURE_MODELS:
+ model_type = (vm.Graph, vm.AgGrid, vm.Table, vm.Figure)
+ models = self.__get_model_children(page) if page is not None else self.__models.values()
+
+ # Convert to list to avoid changing size when looping through at runtime.
+ for model in list(models):
+ if model_type is None or isinstance(model, model_type):
+ yield model
+
+ def __get_model_children(self, model: Model) -> Generator[Model, None, None]:
+ """Iterates through children of `model`.
+
+ Currently looks only through certain fields so might miss some children models.
+ """
+ from vizro.models import VizroBaseModel
+
+ if isinstance(model, VizroBaseModel):
+ yield model
+
+ # TODO: in future this list should not be maintained manually. Instead we should look through all model children
+ # by looking at model.model_fields.
+ model_fields = ["components", "tabs", "controls", "actions", "selector"]
+
+ for model_field in model_fields:
+ if (model_field_value := getattr(model, model_field, None)) is not None:
+ if isinstance(model_field_value, list):
+ # For fields like components that are list of models.
+ for single_model_field_value in model_field_value:
+ yield from self.__get_model_children(single_model_field_value)
+ else:
+ # For fields that have single model like selector.
+ yield from self.__get_model_children(model_field_value)
+ # We don't handle dicts of models at the moment. See below TODO for how this will all be improved in
+ # future.
+
+ # TODO: Add navigation, accordions and other page objects. Won't be needed once have made whole model
+ # manager work better recursively and have better ways to navigate the hierarchy. In pydantic v2 this would use
+ # model_fields. Maybe we'd also use Page (or sometimes Dashboard) as the central model for navigating the
+ # hierarchy rather than it being so generic.
+
+ def _get_model_page(self, model: Model) -> Page: # type: ignore[return]
+ """Gets the page containing `model`."""
from vizro.models import Page
- for page_id, page in model_manager._items_with_type(Page):
- page_model_ids = [page_id, self._get_model_children(model_id=page_id)]
-
- for actions_chain in self._get_page_actions_chains(page_id=page_id):
- page_model_ids.append(actions_chain.id)
- for action in actions_chain.actions:
- page_model_ids.append(action.id) # noqa: PERF401
-
- for control in page.controls:
- page_model_ids.append(control.id)
- if hasattr(control, "selector") and control.selector:
- page_model_ids.append(control.selector.id)
-
- # TODO: Add navigation, accordions and other page objects
-
- if model_id in page_model_ids:
- return cast(ModelID, page.id)
-
- # TODO: Increase the genericity of this method
- def _get_page_actions_chains(self, page_id: ModelID) -> list[ActionsChain]:
- """Gets all ActionsChains present on the page."""
- page = self[page_id]
- page_actions_chains = []
-
- for model_id in self._get_model_children(model_id=page_id):
- model = self[model_id]
- if hasattr(model, "actions"):
- page_actions_chains.extend(model.actions)
-
- for control in page.controls:
- if hasattr(control, "actions") and control.actions:
- page_actions_chains.extend(control.actions)
- if hasattr(control, "selector") and control.selector and hasattr(control.selector, "actions"):
- page_actions_chains.extend(control.selector.actions)
-
- return page_actions_chains
-
- # TODO: Consider moving this one to the _callback_mapping_utils.py since it's only used there
- def _get_action_trigger(self, action_id: ModelID) -> VizroBaseModel: # type: ignore[return]
- """Gets the model that triggers the action with "action_id"."""
- from vizro.models._action._actions_chain import ActionsChain
-
- for _, actions_chain in model_manager._items_with_type(ActionsChain):
- if action_id in [action.id for action in actions_chain.actions]:
- return self[ModelID(str(actions_chain.trigger.component_id))]
-
- def _get_page_model_ids_with_figure(self, page_id: ModelID) -> list[ModelID]:
- """Gets ids of all components from the page that have a 'figure' registered."""
- return [
- model_id
- for model_id in self._get_model_children(model_id=page_id)
- # Optimally this statement should be: "if isinstance(model, Figure)"
- if hasattr(model_manager[model_id], "figure")
- ]
+ if isinstance(model, Page):
+ return model
+
+ for page in cast(Iterable[Page], self._get_models(Page)):
+ if model in self.__get_model_children(page):
+ return page
@staticmethod
def _generate_id() -> ModelID:
diff --git a/vizro-core/src/vizro/models/_action/_action.py b/vizro-core/src/vizro/models/_action/_action.py
index 9aac00ca1..0aef7303b 100644
--- a/vizro-core/src/vizro/models/_action/_action.py
+++ b/vizro-core/src/vizro/models/_action/_action.py
@@ -11,7 +11,6 @@
except ImportError: # pragma: no cov
from pydantic import Field, validator
-from vizro.managers._model_manager import ModelID
from vizro.models import VizroBaseModel
from vizro.models._models_utils import _log_call
from vizro.models.types import CapturedCallable
@@ -79,7 +78,7 @@ def _get_callback_mapping(self):
if self.inputs:
callback_inputs = [State(*input.split(".")) for input in self.inputs]
else:
- callback_inputs = _get_action_callback_mapping(action_id=ModelID(str(self.id)), argument="inputs")
+ callback_inputs = _get_action_callback_mapping(self, argument="inputs")
callback_outputs: Union[list[Output], dict[str, Output]]
if self.outputs:
@@ -91,9 +90,9 @@ def _get_callback_mapping(self):
if len(callback_outputs) == 1:
callback_outputs = callback_outputs[0]
else:
- callback_outputs = _get_action_callback_mapping(action_id=ModelID(str(self.id)), argument="outputs")
+ callback_outputs = _get_action_callback_mapping(self, argument="outputs")
- action_components = _get_action_callback_mapping(action_id=ModelID(str(self.id)), argument="components")
+ action_components = _get_action_callback_mapping(self, argument="components")
return callback_inputs, callback_outputs, action_components
diff --git a/vizro-core/src/vizro/models/_base.py b/vizro-core/src/vizro/models/_base.py
index 40b00deb6..d2f47470e 100644
--- a/vizro-core/src/vizro/models/_base.py
+++ b/vizro-core/src/vizro/models/_base.py
@@ -127,7 +127,7 @@ def _extract_captured_callable_source() -> set[str]:
# Check to see if the captured callable does use a cleaned module string, if yes then
# we can assume that the source code can be imported via Vizro, and thus does not need to be defined
value.__repr_clean__().startswith(new)
- for _, new in REPLACEMENT_STRINGS.items()
+ for new in REPLACEMENT_STRINGS.values()
):
try:
source = textwrap.dedent(inspect.getsource(value._function))
diff --git a/vizro-core/src/vizro/models/_components/ag_grid.py b/vizro-core/src/vizro/models/_components/ag_grid.py
index 25c8aef18..52b1e36a5 100644
--- a/vizro-core/src/vizro/models/_components/ag_grid.py
+++ b/vizro-core/src/vizro/models/_components/ag_grid.py
@@ -10,7 +10,7 @@
from pydantic import Field, PrivateAttr, validator
from dash import ClientsideFunction, Input, Output, clientside_callback
-from vizro.actions._actions_utils import CallbackTriggerDict, _get_component_actions, _get_parent_vizro_model
+from vizro.actions._actions_utils import CallbackTriggerDict, _get_component_actions, _get_parent_model
from vizro.managers import data_manager
from vizro.models import Action, VizroBaseModel
from vizro.models._action._actions_chain import _action_validator_factory
@@ -100,7 +100,7 @@ def _filter_interaction(
return data_frame
# ctd_active_cell["id"] represents the underlying table id, so we need to fetch its parent Vizro Table actions.
- source_table_actions = _get_component_actions(_get_parent_vizro_model(ctd_cellClicked["id"]))
+ source_table_actions = _get_component_actions(_get_parent_model(ctd_cellClicked["id"]))
for action in source_table_actions:
if action.function._function.__name__ != "filter_interaction" or target not in action.function["targets"]:
@@ -119,7 +119,7 @@ def build(self):
clientside_callback(
ClientsideFunction(namespace="dashboard", function_name="update_ag_grid_theme"),
Output(self._input_component_id, "className"),
- Input("theme_selector", "checked"),
+ Input("theme-selector", "value"),
)
return dcc.Loading(
diff --git a/vizro-core/src/vizro/models/_components/button.py b/vizro-core/src/vizro/models/_components/button.py
index 500c8800b..6c95617a2 100644
--- a/vizro-core/src/vizro/models/_components/button.py
+++ b/vizro-core/src/vizro/models/_components/button.py
@@ -1,6 +1,7 @@
from typing import Literal
import dash_bootstrap_components as dbc
+from dash import get_relative_path
try:
from pydantic.v1 import Field
@@ -24,6 +25,7 @@ class Button(VizroBaseModel):
type: Literal["button"] = "button"
text: str = Field("Click me!", description="Text to be displayed on button.")
+ href: str = Field("", description="URL (relative or absolute) to navigate to.")
actions: list[Action] = []
# Re-used validators
@@ -31,4 +33,9 @@ class Button(VizroBaseModel):
@_log_call
def build(self):
- return dbc.Button(id=self.id, children=self.text)
+ return dbc.Button(
+ id=self.id,
+ children=self.text,
+ href=get_relative_path(self.href) if self.href.startswith("/") else self.href,
+ target="_top",
+ )
diff --git a/vizro-core/src/vizro/models/_components/form/_form_utils.py b/vizro-core/src/vizro/models/_components/form/_form_utils.py
index 18e666882..14a20a169 100644
--- a/vizro-core/src/vizro/models/_components/form/_form_utils.py
+++ b/vizro-core/src/vizro/models/_components/form/_form_utils.py
@@ -54,6 +54,9 @@ def validate_value(cls, value, values):
[entry["value"] for entry in values["options"]] if isinstance(values["options"][0], dict) else values["options"]
)
+ if hasattr(value, "__iter__") and ALL_OPTION in value:
+ return value
+
if value and not is_value_contained(value, possible_values):
raise ValueError("Please provide a valid value from `options`.")
diff --git a/vizro-core/src/vizro/models/_components/form/_text_area.py b/vizro-core/src/vizro/models/_components/form/_text_area.py
index 5ac25fdb7..bb1ea7fa1 100644
--- a/vizro-core/src/vizro/models/_components/form/_text_area.py
+++ b/vizro-core/src/vizro/models/_components/form/_text_area.py
@@ -4,9 +4,9 @@
from dash import html
try:
- from pydantic.v1 import Field
+ from pydantic.v1 import Field, PrivateAttr
except ImportError: # pragma: no cov
- from pydantic import Field
+ from pydantic import Field, PrivateAttr
from vizro.models import Action, VizroBaseModel
from vizro.models._action._actions_chain import _action_validator_factory
@@ -32,6 +32,9 @@ class TextArea(VizroBaseModel):
placeholder: str = Field("", description="Default text to display in input field")
actions: list[Action] = []
+ # Component properties for actions and interactions
+ _input_property: str = PrivateAttr("value")
+
# Re-used validators
# TODO: Before making public, consider how actions should be triggered and what the default property should be
# See comment thread: https://github.com/mckinsey/vizro/pull/298#discussion_r1478137654
diff --git a/vizro-core/src/vizro/models/_components/form/_user_input.py b/vizro-core/src/vizro/models/_components/form/_user_input.py
index bb98a14bb..7ca821f65 100644
--- a/vizro-core/src/vizro/models/_components/form/_user_input.py
+++ b/vizro-core/src/vizro/models/_components/form/_user_input.py
@@ -4,9 +4,9 @@
from dash import html
try:
- from pydantic.v1 import Field
+ from pydantic.v1 import Field, PrivateAttr
except ImportError: # pragma: no cov
- from pydantic import Field
+ from pydantic import Field, PrivateAttr
from vizro.models import Action, VizroBaseModel
from vizro.models._action._actions_chain import _action_validator_factory
@@ -32,6 +32,9 @@ class UserInput(VizroBaseModel):
placeholder: str = Field("", description="Default text to display in input field")
actions: list[Action] = []
+ # Component properties for actions and interactions
+ _input_property: str = PrivateAttr("value")
+
# Re-used validators
# TODO: Before making public, consider how actions should be triggered and what the default property should be
# See comment thread: https://github.com/mckinsey/vizro/pull/298#discussion_r1478137654
diff --git a/vizro-core/src/vizro/models/_components/form/checklist.py b/vizro-core/src/vizro/models/_components/form/checklist.py
index 68cb26ad1..d69e725cc 100644
--- a/vizro-core/src/vizro/models/_components/form/checklist.py
+++ b/vizro-core/src/vizro/models/_components/form/checklist.py
@@ -38,6 +38,8 @@ class Checklist(VizroBaseModel):
title: str = Field("", description="Title to be displayed")
actions: list[Action] = []
+ _dynamic: bool = PrivateAttr(False)
+
# Component properties for actions and interactions
_input_property: str = PrivateAttr("value")
@@ -46,9 +48,8 @@ class Checklist(VizroBaseModel):
_validate_options = root_validator(allow_reuse=True, pre=True)(validate_options_dict)
_validate_value = validator("value", allow_reuse=True, always=True)(validate_value)
- @_log_call
- def build(self):
- full_options, default_value = get_options_and_default(options=self.options, multi=True)
+ def __call__(self, options):
+ full_options, default_value = get_options_and_default(options=options, multi=True)
return html.Fieldset(
children=[
@@ -62,3 +63,14 @@ def build(self):
),
]
)
+
+ def _build_dynamic_placeholder(self):
+ if self.value is None:
+ _, default_value = get_options_and_default(self.options, multi=True)
+ self.value = [default_value]
+
+ return self.__call__(self.options)
+
+ @_log_call
+ def build(self):
+ return self._build_dynamic_placeholder() if self._dynamic else self.__call__(self.options)
diff --git a/vizro-core/src/vizro/models/_components/form/dropdown.py b/vizro-core/src/vizro/models/_components/form/dropdown.py
index d0fa24444..aa7f89660 100755
--- a/vizro-core/src/vizro/models/_components/form/dropdown.py
+++ b/vizro-core/src/vizro/models/_components/form/dropdown.py
@@ -65,6 +65,10 @@ class Dropdown(VizroBaseModel):
title: str = Field("", description="Title to be displayed")
actions: list[Action] = []
+ # Consider making the _dynamic public later. The same property could also be used for all other components.
+ # For example: vm.Graph could have a dynamic that is by default set on True.
+ _dynamic: bool = PrivateAttr(False)
+
# Component properties for actions and interactions
_input_property: str = PrivateAttr("value")
@@ -82,9 +86,8 @@ def validate_multi(cls, multi, values):
raise ValueError("Please set multi=True if providing a list of default values.")
return multi
- @_log_call
- def build(self):
- full_options, default_value = get_options_and_default(options=self.options, multi=self.multi)
+ def __call__(self, options):
+ full_options, default_value = get_options_and_default(options=options, multi=self.multi)
option_height = _calculate_option_height(full_options)
return html.Div(
@@ -95,9 +98,24 @@ def build(self):
options=full_options,
value=self.value if self.value is not None else default_value,
multi=self.multi,
- persistence=True,
optionHeight=option_height,
+ persistence=True,
persistence_type="session",
),
]
)
+
+ def _build_dynamic_placeholder(self):
+ # Setting self.value is kind of Dropdown pre_build method. It sets self.value only the first time if it's None.
+ # We cannot create pre_build for the Dropdown because it has to be called after vm.Filter.pre_build, but nothing
+ # guarantees that. We can call Filter.selector.pre_build() from the Filter.pre_build() method if we decide that.
+ # TODO: move this to pre_build once we have better control of the ordering.
+ if self.value is None:
+ _, default_value = get_options_and_default(self.options, self.multi)
+ self.value = default_value
+
+ return self.__call__(self.options)
+
+ @_log_call
+ def build(self):
+ return self._build_dynamic_placeholder() if self._dynamic else self.__call__(self.options)
diff --git a/vizro-core/src/vizro/models/_components/form/radio_items.py b/vizro-core/src/vizro/models/_components/form/radio_items.py
index dfa282126..25b67beef 100644
--- a/vizro-core/src/vizro/models/_components/form/radio_items.py
+++ b/vizro-core/src/vizro/models/_components/form/radio_items.py
@@ -39,6 +39,8 @@ class RadioItems(VizroBaseModel):
title: str = Field("", description="Title to be displayed")
actions: list[Action] = []
+ _dynamic: bool = PrivateAttr(False)
+
# Component properties for actions and interactions
_input_property: str = PrivateAttr("value")
@@ -47,9 +49,8 @@ class RadioItems(VizroBaseModel):
_validate_options = root_validator(allow_reuse=True, pre=True)(validate_options_dict)
_validate_value = validator("value", allow_reuse=True, always=True)(validate_value)
- @_log_call
- def build(self):
- full_options, default_value = get_options_and_default(options=self.options, multi=False)
+ def __call__(self, options):
+ full_options, default_value = get_options_and_default(options=options, multi=False)
return html.Fieldset(
children=[
@@ -63,3 +64,14 @@ def build(self):
),
]
)
+
+ def _build_dynamic_placeholder(self):
+ if self.value is None:
+ _, default_value = get_options_and_default(self.options, multi=False)
+ self.value = default_value
+
+ return self.__call__(self.options)
+
+ @_log_call
+ def build(self):
+ return self._build_dynamic_placeholder() if self._dynamic else self.__call__(self.options)
diff --git a/vizro-core/src/vizro/models/_components/form/range_slider.py b/vizro-core/src/vizro/models/_components/form/range_slider.py
index 16f0cb8c9..a96521708 100644
--- a/vizro-core/src/vizro/models/_components/form/range_slider.py
+++ b/vizro-core/src/vizro/models/_components/form/range_slider.py
@@ -50,6 +50,8 @@ class RangeSlider(VizroBaseModel):
title: str = Field("", description="Title to be displayed.")
actions: list[Action] = []
+ _dynamic: bool = PrivateAttr(False)
+
# Component properties for actions and interactions
_input_property: str = PrivateAttr("value")
@@ -60,10 +62,7 @@ class RangeSlider(VizroBaseModel):
_set_default_marks = validator("marks", allow_reuse=True, always=True)(set_default_marks)
_set_actions = _action_validator_factory("value")
- @_log_call
- def build(self):
- init_value = self.value or [self.min, self.max] # type: ignore[list-item]
-
+ def __call__(self, min, max, current_value):
output = [
Output(f"{self.id}_start_value", "value"),
Output(f"{self.id}_end_value", "value"),
@@ -86,7 +85,7 @@ def build(self):
return html.Div(
children=[
- dcc.Store(f"{self.id}_callback_data", data={"id": self.id, "min": self.min, "max": self.max}),
+ dcc.Store(f"{self.id}_callback_data", data={"id": self.id, "min": min, "max": max}),
html.Div(
children=[
dbc.Label(children=self.title, html_for=self.id) if self.title else None,
@@ -96,10 +95,10 @@ def build(self):
id=f"{self.id}_start_value",
type="number",
placeholder="min",
- min=self.min,
- max=self.max,
+ min=min,
+ max=max,
step=self.step,
- value=init_value[0],
+ value=current_value[0],
persistence=True,
persistence_type="session",
className="slider-text-input-field",
@@ -109,15 +108,15 @@ def build(self):
id=f"{self.id}_end_value",
type="number",
placeholder="max",
- min=self.min,
- max=self.max,
+ min=min,
+ max=max,
step=self.step,
- value=init_value[1],
+ value=current_value[1],
persistence=True,
persistence_type="session",
className="slider-text-input-field",
),
- dcc.Store(id=f"{self.id}_input_store", storage_type="session", data=init_value),
+ dcc.Store(id=f"{self.id}_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
@@ -126,14 +125,26 @@ def build(self):
),
dcc.RangeSlider(
id=self.id,
- min=self.min,
- max=self.max,
+ min=min,
+ max=max,
step=self.step,
marks=self.marks,
- value=init_value,
+ value=current_value,
persistence=True,
persistence_type="session",
className="slider-track-without-marks" if self.marks is None else "slider-track-with-marks",
),
]
)
+
+ def _build_dynamic_placeholder(self, current_value):
+ return self.__call__(self.min, self.max, current_value)
+
+ @_log_call
+ def build(self):
+ current_value = self.value or [self.min, self.max] # type: ignore[list-item]
+ return (
+ self._build_dynamic_placeholder(current_value)
+ if self._dynamic
+ else self.__call__(self.min, self.max, current_value)
+ )
diff --git a/vizro-core/src/vizro/models/_components/form/slider.py b/vizro-core/src/vizro/models/_components/form/slider.py
index 65b37fe9a..2ffdb9f6a 100644
--- a/vizro-core/src/vizro/models/_components/form/slider.py
+++ b/vizro-core/src/vizro/models/_components/form/slider.py
@@ -48,6 +48,8 @@ class Slider(VizroBaseModel):
title: str = Field("", description="Title to be displayed.")
actions: list[Action] = []
+ _dynamic: bool = PrivateAttr(False)
+
# Component properties for actions and interactions
_input_property: str = PrivateAttr("value")
@@ -58,10 +60,7 @@ class Slider(VizroBaseModel):
_set_default_marks = validator("marks", allow_reuse=True, always=True)(set_default_marks)
_set_actions = _action_validator_factory("value")
- @_log_call
- def build(self):
- init_value = self.value or self.min
-
+ def __call__(self, min, max, current_value):
output = [
Output(f"{self.id}_end_value", "value"),
Output(self.id, "value"),
@@ -82,7 +81,7 @@ def build(self):
return html.Div(
children=[
- dcc.Store(f"{self.id}_callback_data", data={"id": self.id, "min": self.min, "max": self.max}),
+ dcc.Store(f"{self.id}_callback_data", data={"id": self.id, "min": min, "max": max}),
html.Div(
children=[
dbc.Label(children=self.title, html_for=self.id) if self.title else None,
@@ -92,15 +91,15 @@ def build(self):
id=f"{self.id}_end_value",
type="number",
placeholder="max",
- min=self.min,
- max=self.max,
+ min=min,
+ max=max,
step=self.step,
- value=init_value,
+ value=current_value,
persistence=True,
persistence_type="session",
className="slider-text-input-field",
),
- dcc.Store(id=f"{self.id}_input_store", storage_type="session", data=init_value),
+ dcc.Store(id=f"{self.id}_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
@@ -109,11 +108,11 @@ def build(self):
),
dcc.Slider(
id=self.id,
- min=self.min,
- max=self.max,
+ min=min,
+ max=max,
step=self.step,
marks=self.marks,
- value=init_value,
+ value=current_value,
included=False,
persistence=True,
persistence_type="session",
@@ -121,3 +120,15 @@ def build(self):
),
]
)
+
+ def _build_dynamic_placeholder(self, current_value):
+ return self.__call__(self.min, self.max, current_value)
+
+ @_log_call
+ def build(self):
+ current_value = self.value if self.value is not None else self.min
+ return (
+ self._build_dynamic_placeholder(current_value)
+ if self._dynamic
+ else self.__call__(self.min, self.max, current_value)
+ )
diff --git a/vizro-core/src/vizro/models/_components/graph.py b/vizro-core/src/vizro/models/_components/graph.py
index 1250a2992..8772975c6 100644
--- a/vizro-core/src/vizro/models/_components/graph.py
+++ b/vizro-core/src/vizro/models/_components/graph.py
@@ -168,7 +168,7 @@ def build(self):
output=[Output(self.id, "figure"), Output(self.id, "style")],
inputs=[
Input(self.id, "figure"),
- Input("theme_selector", "checked"),
+ Input("theme-selector", "value"),
State("vizro_themes", "data"),
],
prevent_initial_call=True,
diff --git a/vizro-core/src/vizro/models/_components/table.py b/vizro-core/src/vizro/models/_components/table.py
index 8ffb4ea8d..edfea4c5c 100644
--- a/vizro-core/src/vizro/models/_components/table.py
+++ b/vizro-core/src/vizro/models/_components/table.py
@@ -9,7 +9,7 @@
except ImportError: # pragma: no cov
from pydantic import Field, PrivateAttr, validator
-from vizro.actions._actions_utils import CallbackTriggerDict, _get_component_actions, _get_parent_vizro_model
+from vizro.actions._actions_utils import CallbackTriggerDict, _get_component_actions, _get_parent_model
from vizro.managers import data_manager
from vizro.models import Action, VizroBaseModel
from vizro.models._action._actions_chain import _action_validator_factory
@@ -104,7 +104,7 @@ def _filter_interaction(
return data_frame
# ctd_active_cell["id"] represents the underlying table id, so we need to fetch its parent Vizro Table actions.
- source_table_actions = _get_component_actions(_get_parent_vizro_model(ctd_active_cell["id"]))
+ source_table_actions = _get_component_actions(_get_parent_model(ctd_active_cell["id"]))
for action in source_table_actions:
if action.function._function.__name__ != "filter_interaction" or target not in action.function["targets"]:
diff --git a/vizro-core/src/vizro/models/_components/tabs.py b/vizro-core/src/vizro/models/_components/tabs.py
index bd19f40cf..099d2f1d9 100644
--- a/vizro-core/src/vizro/models/_components/tabs.py
+++ b/vizro-core/src/vizro/models/_components/tabs.py
@@ -2,8 +2,7 @@
from typing import TYPE_CHECKING, Literal
-import dash_mantine_components as dmc
-from dash import html
+import dash_bootstrap_components as dbc
try:
from pydantic.v1 import validator
@@ -33,21 +32,9 @@ class Tabs(VizroBaseModel):
@_log_call
def build(self):
- tabs_list = dmc.TabsList(
- [dmc.Tab(tab.title, value=tab.id, className="tab-title") for tab in self.tabs],
- className="tabs-list",
- )
-
- tabs_panels = [
- dmc.TabsPanel(html.Div([tab.build()], className="tab-content"), value=tab.id, className="tabs-panel")
- for tab in self.tabs
- ]
-
- return dmc.Tabs(
+ return dbc.Tabs(
id=self.id,
- value=self.tabs[0].id,
- children=[tabs_list, *tabs_panels],
+ children=[dbc.Tab(tab.build(), label=tab.title) for tab in self.tabs],
persistence=True,
persistence_type="session",
- className="tabs",
)
diff --git a/vizro-core/src/vizro/models/_controls/filter.py b/vizro-core/src/vizro/models/_controls/filter.py
index 683e7f870..8a18add8e 100644
--- a/vizro-core/src/vizro/models/_controls/filter.py
+++ b/vizro-core/src/vizro/models/_controls/filter.py
@@ -1,9 +1,10 @@
from __future__ import annotations
-from typing import Any, Literal, Union
+from collections.abc import Iterable
+from typing import Any, Literal, Union, cast
-import numpy as np
import pandas as pd
+from dash import dcc
from pandas.api.types import is_datetime64_any_dtype, is_numeric_dtype
from vizro.managers._data_manager import DataSourceName
@@ -13,10 +14,11 @@
except ImportError: # pragma: no cov
from pydantic import Field, PrivateAttr, validator
-from vizro._constants import FILTER_ACTION_PREFIX
+from vizro._constants import ALL_OPTION, FILTER_ACTION_PREFIX
from vizro.actions import _filter
from vizro.managers import data_manager, model_manager
-from vizro.managers._model_manager import ModelID
+from vizro.managers._data_manager import _DynamicData
+from vizro.managers._model_manager import FIGURE_MODELS, ModelID
from vizro.models import Action, VizroBaseModel
from vizro.models._components.form import (
Checklist,
@@ -46,6 +48,10 @@
"categorical": SELECTORS["numerical"] + SELECTORS["temporal"],
}
+# TODO: Remove DYNAMIC_SELECTORS along with its validation check when support dynamic mode for the DatePicker selector.
+# Tuple of filter selectors that support dynamic mode
+DYNAMIC_SELECTORS = (Dropdown, Checklist, RadioItems, Slider, RangeSlider)
+
def _filter_between(series: pd.Series, value: Union[list[float], list[str]]) -> pd.Series:
if is_datetime64_any_dtype(series):
@@ -88,6 +94,12 @@ class Filter(VizroBaseModel):
"If none are given then target all components on the page that use `column`.",
)
selector: SelectorType = None
+
+ _dynamic: bool = PrivateAttr(False)
+
+ # Component properties for actions and interactions
+ _output_component_property: str = PrivateAttr("children")
+
_column_type: Literal["numerical", "categorical", "temporal"] = PrivateAttr()
@validator("targets", each_item=True)
@@ -96,24 +108,53 @@ def check_target_present(cls, target):
raise ValueError(f"Target {target} not found in model_manager.")
return target
+ def __call__(self, target_to_data_frame: dict[ModelID, pd.DataFrame], current_value: Any):
+ # Only relevant for a dynamic filter.
+ # Although targets are fixed at build time, the validation logic is repeated during runtime, so if a column
+ # is missing then it will raise an error. We could change this if we wanted.
+ targeted_data = self._validate_targeted_data(
+ {target: data_frame for target, data_frame in target_to_data_frame.items() if target in self.targets},
+ eagerly_raise_column_not_found_error=True,
+ )
+
+ if (column_type := self._validate_column_type(targeted_data)) != self._column_type:
+ raise ValueError(
+ f"{self.column} has changed type from {self._column_type} to {column_type}. A filtered column cannot "
+ "change type while the dashboard is running."
+ )
+
+ if isinstance(self.selector, SELECTORS["categorical"]):
+ return self.selector(options=self._get_options(targeted_data, current_value))
+ else:
+ _min, _max = self._get_min_max(targeted_data, current_value)
+ # "current_value" is propagated only to support dcc.Input and dcc.Store components in numerical selectors
+ # to work with a dynamic selector. This can be removed when dash persistence bug is fixed.
+ return self.selector(min=_min, max=_max, current_value=current_value)
+
@_log_call
def pre_build(self):
# If targets aren't explicitly provided then try to target all figures on the page. In this case we don't
# want to raise an error if the column is not found in a figure's data_frame, it will just be ignored.
# This is the case when bool(self.targets) is False.
# Possibly in future this will change (which would be breaking change).
- proposed_targets = self.targets or model_manager._get_page_model_ids_with_figure(
- page_id=model_manager._get_model_page_id(model_id=ModelID(str(self.id)))
- )
- # TODO NEXT: how to handle pre_build for dynamic filters? Do we still require default argument values in
- # `load` to establish selector type etc.? Can we take selector values from model_manager to supply these?
- # Or just don't do validation at pre_build time and wait until state is available during build time instead?
- # What should the load kwargs be here? Remember they need to be {} for static data.
- # Note that currently _get_unfiltered_data is only suitable for use at runtime since it requires
- # ctd_parameters. That could be changed to just reuse that function.
+ proposed_targets = self.targets or [
+ cast(ModelID, model.id)
+ for model in cast(
+ Iterable[VizroBaseModel], model_manager._get_models(FIGURE_MODELS, model_manager._get_model_page(self))
+ )
+ ]
+ # TODO: Currently dynamic data functions require a default value for every argument. Even when there is a
+ # dataframe parameter, the default value is used when pre-build the filter e.g. to find the targets,
+ # column type (and hence selector) and initial values. There are three ways to handle this:
+ # 1. (Current approach) - Propagate {} and use only default arguments value in the dynamic data function.
+ # 2. Propagate values from the model_manager and relax the limitation of requiring argument default values.
+ # 3. Skip the pre-build and do everything in the build method (if possible).
+ # Find more about the mentioned limitation at: https://github.com/mckinsey/vizro/pull/879/files#r1846609956
+ # Even if the solution changes for dynamic data, static data should still use {} as the arguments here.
multi_data_source_name_load_kwargs: list[tuple[DataSourceName, dict[str, Any]]] = [
(model_manager[target]["data_frame"], {}) for target in proposed_targets
]
+
target_to_data_frame = dict(zip(proposed_targets, data_manager._multi_load(multi_data_source_name_load_kwargs)))
targeted_data = self._validate_targeted_data(
target_to_data_frame, eagerly_raise_column_not_found_error=bool(self.targets)
@@ -131,6 +172,23 @@ def pre_build(self):
f"'{self.column}'."
)
+ # Check if the filter is dynamic. Dynamic filter means that the filter is updated when the page is refreshed
+ # which causes "options" for categorical or "min" and "max" for numerical/temporal selectors to be updated.
+ # The filter is dynamic iff mentioned attributes ("options"/"min"/"max") are not explicitly provided and
+ # filter targets at least one figure that uses dynamic data source. Note that min or max = 0 are Falsey values
+ # but should still count as manually set.
+ if isinstance(self.selector, DYNAMIC_SELECTORS) and (
+ not getattr(self.selector, "options", [])
+ and getattr(self.selector, "min", None) is None
+ and getattr(self.selector, "max", None) is None
+ ):
+ for target_id in self.targets:
+ data_source_name = model_manager[target_id]["data_frame"]
+ if isinstance(data_manager[data_source_name], _DynamicData):
+ self._dynamic = True
+ self.selector._dynamic = True
+ break
+
# Set appropriate properties for the selector.
if isinstance(self.selector, SELECTORS["numerical"] + SELECTORS["temporal"]):
_min, _max = self._get_min_max(targeted_data)
@@ -158,32 +216,33 @@ def pre_build(self):
)
]
- def __call__(self, target_to_data_frame: dict[ModelID, pd.DataFrame]):
- # Only relevant for a dynamic filter.
- # Although targets are fixed at build time, the validation logic is repeated during runtime, so if a column
- # is missing then it will raise an error. We could change this if we wanted.
- # Call this from actions_utils
- targeted_data = self._validate_targeted_data(
- {target: data_frame for target, data_frame in target_to_data_frame.items() if target in self.targets},
- eagerly_raise_column_not_found_error=True,
- )
-
- if (column_type := self._validate_column_type(targeted_data)) != self._column_type:
- raise ValueError(
- f"{self.column} has changed type from {self._column_type} to {column_type}. A filtered column cannot "
- "change type while the dashboard is running."
- )
-
- # TODO: when implement dynamic, will need to do something with this e.g. pass to selector.__call__.
- # if isinstance(self.selector, SELECTORS["numerical"] + SELECTORS["temporal"]):
- # options = self._get_options(targeted_data)
- # else:
- # # Categorical selector.
- # _min, _max = self._get_min_max(targeted_data)
-
@_log_call
def build(self):
- return self.selector.build()
+ selector_build_obj = self.selector.build()
+ # TODO: Align the (dynamic) object's return structure with the figure's components when the Dash bug is fixed.
+ # This means returning an empty "html.Div(id=self.id, className=...)" as a placeholder from Filter.build().
+ # Also, make selector.title visible when the filter is reloading.
+ if not self._dynamic:
+ return selector_build_obj
+
+ # Temporarily hide the selector and numeric dcc.Input components during the filter reloading process.
+ # Other components, such as the title, remain visible because of the configuration:
+ # overlay_style={"visibility": "visible"} in dcc.Loading.
+ # Note: dcc.Slider and dcc.RangeSlider do not support the "style" property directly,
+ # so the "className" attribute is used to apply custom CSS for visibility control.
+ # Reference for Dash class names: https://dashcheatsheet.pythonanywhere.com/
+ selector_build_obj[self.selector.id].className = "invisible"
+ if f"{self.selector.id}_start_value" in selector_build_obj:
+ selector_build_obj[f"{self.selector.id}_start_value"].className = "d-none"
+ if f"{self.selector.id}_end_value" in selector_build_obj:
+ selector_build_obj[f"{self.selector.id}_end_value"].className = "d-none"
+
+ return dcc.Loading(
+ id=self.id,
+ children=selector_build_obj,
+ color="grey",
+ overlay_style={"visibility": "visible"},
+ )
def _validate_targeted_data(
self, target_to_data_frame: dict[ModelID, pd.DataFrame], eagerly_raise_column_not_found_error
@@ -205,6 +264,7 @@ def _validate_targeted_data(
f"Selected column {self.column} not found in any dataframe for "
f"{', '.join(target_to_data_frame.keys())}."
)
+ # TODO: Enable empty data_frame handling
if targeted_data.empty:
raise ValueError(
f"Selected column {self.column} does not contain anything in any dataframe for "
@@ -231,17 +291,24 @@ def _validate_column_type(self, targeted_data: pd.DataFrame) -> Literal["numeric
)
@staticmethod
- def _get_min_max(targeted_data: pd.DataFrame) -> tuple[float, float]:
+ def _get_min_max(targeted_data: pd.DataFrame, current_value=None) -> tuple[float, float]:
+ targeted_data = pd.concat([targeted_data, pd.Series(current_value)]).stack().dropna() # noqa: PD013
+
+ _min = targeted_data.min(axis=None)
+ _max = targeted_data.max(axis=None)
+
# Use item() to convert to convert scalar from numpy to Python type. This isn't needed during pre_build because
# pydantic will coerce the type, but it is necessary in __call__ where we don't update model field values
# and instead just pass straight to the Dash component.
- return targeted_data.min(axis=None).item(), targeted_data.max(axis=None).item()
+ # However, in some cases _min and _max are already Python types and so item() call is not required.
+ _min = _min if not hasattr(_min, "item") else _min.item()
+ _max = _max if not hasattr(_max, "item") else _max.item()
+
+ return _min, _max
@staticmethod
- def _get_options(targeted_data: pd.DataFrame) -> list[Any]:
- # Use tolist() to convert to convert scalar from numpy to Python type. This isn't needed during pre_build
- # because pydantic will coerce the type, but it is necessary in __call__ where we don't update model field
- # values and instead just pass straight to the Dash component.
+ def _get_options(targeted_data: pd.DataFrame, current_value=None) -> list[Any]:
# The dropna() isn't strictly required here but will be in future pandas versions when the behavior of stack
# changes. See https://pandas.pydata.org/docs/whatsnew/v2.1.0.html#whatsnew-210-enhancements-new-stack.
- return np.unique(targeted_data.stack().dropna()).tolist() # noqa: PD013
+ targeted_data = pd.concat([targeted_data, pd.Series(current_value)]).stack().dropna() # noqa: PD013
+ return sorted(set(targeted_data) - {ALL_OPTION})
diff --git a/vizro-core/src/vizro/models/_controls/parameter.py b/vizro-core/src/vizro/models/_controls/parameter.py
index e7d6d537c..cdc76936c 100644
--- a/vizro-core/src/vizro/models/_controls/parameter.py
+++ b/vizro-core/src/vizro/models/_controls/parameter.py
@@ -1,4 +1,5 @@
-from typing import Literal
+from collections.abc import Iterable
+from typing import Literal, cast
try:
from pydantic.v1 import Field, validator
@@ -55,12 +56,13 @@ def check_data_frame_as_target_argument(cls, target):
f"Invalid target {target}. 'data_frame' target must be supplied in the form "
".data_frame."
)
+ # TODO: Add validation: Make sure the target data_frame is _DynamicData.
return target
@validator("targets")
def check_duplicate_parameter_target(cls, targets):
all_targets = targets.copy()
- for _, param in model_manager._items_with_type(Parameter):
+ for param in cast(Iterable[Parameter], model_manager._get_models(Parameter)):
all_targets.extend(param.targets)
duplicate_targets = {item for item in all_targets if all_targets.count(item) > 1}
if duplicate_targets:
diff --git a/vizro-core/src/vizro/models/_dashboard.py b/vizro-core/src/vizro/models/_dashboard.py
index 4b3b0e66a..b635b8e95 100644
--- a/vizro-core/src/vizro/models/_dashboard.py
+++ b/vizro-core/src/vizro/models/_dashboard.py
@@ -8,7 +8,6 @@
import dash
import dash_bootstrap_components as dbc
-import dash_mantine_components as dmc
import plotly.io as pio
from dash import (
ClientsideFunction,
@@ -142,7 +141,7 @@ def build(self):
ClientsideFunction(namespace="dashboard", function_name="update_dashboard_theme"),
# This currently doesn't do anything, but we need to define an Output such that the callback is triggered.
Output("dashboard-container", "className"),
- Input("theme_selector", "checked"),
+ Input("theme-selector", "value"),
)
left_side_div_present = any([len(self.pages) > 1, self.pages[0].controls])
if left_side_div_present:
@@ -197,12 +196,11 @@ def _get_page_divs(self, page: Page) -> _PageDivsType:
else html.H2(id="dashboard-title", hidden=True)
)
settings = html.Div(
- children=dmc.Switch(
- id="theme_selector",
- checked=self.theme == "vizro_light",
+ children=dbc.Switch(
+ id="theme-selector",
+ value=self.theme == "vizro_light",
persistence=True,
persistence_type="session",
- className="toggle-switch",
),
id="settings",
)
@@ -310,32 +308,18 @@ def _make_page_404_layout(self):
return html.Div(
[
# Theme switch is added such that the 404 page has the same theme as the user-selected one.
- html.Div(
- children=dmc.Switch(
- id="theme_selector",
- checked=self.theme == "vizro_light",
- persistence=True,
- persistence_type="session",
- className="toggle-switch",
- ),
- id="settings",
+ dbc.Switch(
+ id="theme-selector",
+ value=self.theme == "vizro_light",
+ persistence=True,
+ persistence_type="session",
),
html.Img(src=f"data:image/svg+xml;base64,{error_404_svg}"),
- html.Div(
- [
- html.Div(
- children=[
- html.H3("This page could not be found.", className="heading-3-600"),
- html.P("Make sure the URL you entered is correct."),
- ],
- className="error-text-container",
- ),
- dbc.Button(children="Take me home", href=get_relative_path("/")),
- ],
- className="error-content-container",
- ),
+ html.H3("This page could not be found."),
+ html.P("Make sure the URL you entered is correct."),
+ dbc.Button(children="Take me home", href=get_relative_path("/"), className="mt-4"),
],
- className="page-error-container",
+ className="d-flex flex-column align-items-center justify-content-center min-vh-100",
)
@staticmethod
diff --git a/vizro-core/src/vizro/models/_navigation/_navigation_utils.py b/vizro-core/src/vizro/models/_navigation/_navigation_utils.py
index 7e8e1f15f..387cf8b9a 100644
--- a/vizro-core/src/vizro/models/_navigation/_navigation_utils.py
+++ b/vizro-core/src/vizro/models/_navigation/_navigation_utils.py
@@ -1,7 +1,8 @@
from __future__ import annotations
import itertools
-from typing import TypedDict
+from collections.abc import Iterable
+from typing import TypedDict, cast
import dash_bootstrap_components as dbc
@@ -15,8 +16,7 @@ def _validate_pages(pages):
pages_as_list = list(itertools.chain(*pages.values())) if isinstance(pages, dict) else pages
# Ideally we would use dashboard.pages in the model manager here, but we only register pages in
# dashboard.pre_build and model manager cannot find a Dashboard at validation time.
- # page[0] gives the page model ID.
- registered_pages = [page[0] for page in model_manager._items_with_type(Page)]
+ registered_pages = [page.id for page in cast(Iterable[Page], model_manager._get_models(Page))]
if not pages_as_list:
raise ValueError("Ensure this value has at least 1 item.")
diff --git a/vizro-core/src/vizro/models/_page.py b/vizro-core/src/vizro/models/_page.py
index 6b45a409c..e137987bb 100644
--- a/vizro-core/src/vizro/models/_page.py
+++ b/vizro-core/src/vizro/models/_page.py
@@ -1,7 +1,7 @@
from __future__ import annotations
-from collections.abc import Mapping
-from typing import Any, Optional, TypedDict, Union
+from collections.abc import Iterable, Mapping
+from typing import Any, Optional, TypedDict, Union, cast
from dash import dcc, html
@@ -13,8 +13,8 @@
from vizro._constants import ON_PAGE_LOAD_ACTION_PREFIX
from vizro.actions import _on_page_load
from vizro.managers import model_manager
-from vizro.managers._model_manager import DuplicateIDError, ModelID
-from vizro.models import Action, Layout, VizroBaseModel
+from vizro.managers._model_manager import FIGURE_MODELS, DuplicateIDError
+from vizro.models import Action, Filter, Layout, VizroBaseModel
from vizro.models._action._actions_chain import ActionsChain, Trigger
from vizro.models._layout import set_layout
from vizro.models._models_utils import _log_call, check_captured_callable, validate_min_length
@@ -96,8 +96,16 @@ def __vizro_exclude_fields__(self) -> Optional[Union[set[str], Mapping[str, Any]
@_log_call
def pre_build(self):
- # TODO: Remove default on page load action if possible
- targets = model_manager._get_page_model_ids_with_figure(page_id=ModelID(str(self.id)))
+ figure_targets = [
+ model.id for model in cast(Iterable[VizroBaseModel], model_manager._get_models(FIGURE_MODELS, page=self))
+ ]
+ filter_targets = [
+ filter.id
+ for filter in cast(Iterable[Filter], model_manager._get_models(Filter, page=self))
+ if filter._dynamic
+ ]
+ targets = figure_targets + filter_targets
+
if targets:
self.actions = [
ActionsChain(
diff --git a/vizro-core/src/vizro/static/css/aggrid.css b/vizro-core/src/vizro/static/css/aggrid.css
index 81d463b9b..286e28d0b 100644
--- a/vizro-core/src/vizro/static/css/aggrid.css
+++ b/vizro-core/src/vizro/static/css/aggrid.css
@@ -1,27 +1,27 @@
.ag-theme-quartz.ag-theme-vizro,
.ag-theme-quartz-dark.ag-theme-vizro {
- --ag-active-color: var(--state-overlays-selected-hover);
- --ag-background-color: var(--main-container-bg-color);
- --ag-odd-row-background-color: var(--main-container-bg-color);
+ --ag-active-color: var(--stateOverlays-selectedHover);
+ --ag-background-color: var(--right-side-bg);
+ --ag-odd-row-background-color: var(--right-side-bg);
--ag-header-foreground-color: var(--text-secondary);
--ag-data-color: var(--text-primary);
- --ag-header-background-color: var(--main-container-bg-color);
+ --ag-header-background-color: var(--right-side-bg);
--ag-icon-font-family: aggridquartz;
- --ag-icon-size: var(--text-size-02);
+ --ag-icon-size: 0.875rem;
--ag-row-height: 48px;
--ag-header-height: 40px;
--ag-borders: none;
--ag-border-radius: 0;
--ag-border-color: transparent;
--ag-row-border-style: solid;
- --ag-row-border-color: var(--border-subtle-alpha-01);
+ --ag-row-border-color: var(--border-subtleAlpha01);
--ag-row-border-width: 1px;
- --ag-selected-row-background-color: var(--state-overlays-selected);
+ --ag-selected-row-background-color: var(--stateOverlays-selected);
--ag-checkbox-checked-color: var(--text-primary);
--ag-header-column-resize-handle-display: block;
--ag-header-column-resize-handle-height: 30%;
--ag-header-column-resize-handle-width: 1px;
- --ag-header-column-resize-handle-color: var(--border-subtle-alpha-02);
+ --ag-header-column-resize-handle-color: var(--border-subtleAlpha02);
--ag-range-selection-border-color: transparent;
--ag-input-focus-border-color: transparent;
}
@@ -29,7 +29,7 @@
/* Header ------- */
#dashboard-container .ag-header-row {
align-items: flex-start;
- border-bottom: 1px solid var(--border-subtle-alpha-02);
+ border-bottom: 1px solid var(--border-subtleAlpha02);
display: flex;
}
@@ -37,12 +37,12 @@
align-items: center;
display: flex;
height: 40px;
- padding: 0 var(--spacing-03);
+ padding: 0 0.75rem;
}
#dashboard-container .ag-header-cell-text {
letter-spacing: -0.112px;
- line-height: var(--spacing-04);
+ line-height: 1rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -55,7 +55,7 @@
/* Rows ------- */
#dashboard-container .ag-cell {
- padding: 0 var(--spacing-03);
+ padding: 0 0.75rem;
}
#dashboard-container .ag-cell-focus {
@@ -63,24 +63,24 @@
}
#dashboard-container .ag-cell-focus:not(.ag-cell-range-selected):focus-within {
- background: var(--state-overlays-selected);
+ background: var(--stateOverlays-selected);
}
/* Pop up menu ----- */
#dashboard-container .ag-menu {
- background-color: var(--surfaces-bg-02);
- border: 1px solid var(--border-subtle-alpha-02);
+ background-color: var(--surfaces-bg02);
+ border: 1px solid var(--border-subtleAlpha02);
color: var(--text-primary);
}
#dashboard-container .ag-ltr .ag-filter-filter input {
background-color: var(--field-enabled);
- box-shadow: var(--box-shadow-elevation-0);
+ box-shadow: var(--elevation-0);
display: flex;
- font-size: var(--text-size-02);
- font-weight: var(--text-weight-regular);
- letter-spacing: var(--letter-spacing-body-ui-02);
- line-height: var(--text-size-03);
+ font-size: 0.875rem;
+ font-weight: 400;
+ letter-spacing: -0.112px;
+ line-height: 1rem;
text-overflow: ellipsis;
}
@@ -89,24 +89,24 @@
border: none;
border-radius: 0;
box-shadow: none;
- font-size: var(--text-size-02);
+ font-size: 0.875rem;
}
#dashboard-container .ag-filter-select .ag-picker-field-wrapper {
background-color: var(--field-enabled);
- box-shadow: var(--box-shadow-elevation-0);
+ box-shadow: var(--elevation-0);
}
#dashboard-container .ag-select-list {
background-color: var(--field-enabled);
- box-shadow: var(--box-shadow-elevation-0);
+ box-shadow: var(--elevation-0);
color: var(--text-primary);
- font-size: var(--text-size-02);
- line-height: var(--text-size-05);
+ font-size: 0.875rem;
+ line-height: 1.5rem;
}
#dashboard-container .ag-select-list-item.ag-active-item {
- background-color: var(--state-overlays-hover);
+ background-color: var(--stateOverlays-hover);
}
#dashboard-container .ag-radio-button-input-wrapper {
@@ -123,12 +123,12 @@
#dashboard-container .ag-filter-apply-panel {
justify-content: flex-start;
- padding: var(--spacing-02) 0 var(--spacing-03) 0;
+ padding: 0.5rem 0 0.75rem;
}
#dashboard-container .ag-filter-condition {
justify-content: flex-start;
- padding: var(--spacing-02) var(--spacing-01);
+ padding: 0.5rem 0.25rem;
}
/* Scroll Bar */
@@ -157,28 +157,27 @@
padding-left: 0;
}
-/* Buttons */
#dashboard-container .ag-standard-button {
background: var(--fill-active);
border: none;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
- color: var(--text-contrast-primary);
- font-size: var(--text-size-02);
- font-weight: var(--text-weight-semibold);
+ box-shadow: var(--elevation-0);
+ color: var(--text-primary-inverted);
+ font-size: 0.875rem;
+ font-weight: 600;
height: 32px;
- letter-spacing: var(--letter-spacing-body-link-02);
- line-height: var(--text-size-05);
- padding: var(--spacing-01) var(--spacing-03);
+ letter-spacing: -0.028px;
+ line-height: 1.5rem;
+ padding: 0.25rem 0.75rem;
text-transform: none;
}
#dashboard-container .ag-standard-button:hover {
background: linear-gradient(
- var(--state-overlays-contrast-hover),
- var(--state-overlays-contrast-hover)
+ var(--stateOverlays-hover-inverted),
+ var(--stateOverlays-hover-inverted)
),
var(--fill-active);
- color: var(--text-contrast-primary);
+ color: var(--text-primary-inverted);
text-decoration-line: underline;
}
diff --git a/vizro-core/src/vizro/static/css/bootstrap_overwrites.css b/vizro-core/src/vizro/static/css/bootstrap_overwrites.css
index 59197a251..7384ffe6d 100644
--- a/vizro-core/src/vizro/static/css/bootstrap_overwrites.css
+++ b/vizro-core/src/vizro/static/css/bootstrap_overwrites.css
@@ -1,6 +1,34 @@
-/* This file contains overwrites, which we want to have as defaults for vizro
-but do not want to take over to `vizro-bootstrap` as these settings might not be generic enough. */
+/* This file contains overwrites, which we want to have as defaults for vizro framework
+but do not want to take over to `vizro-bootstrap` as these settings might not be generic enough
+for a pure Dash app.
+All the HEX values starting with --text-code are taken from the Github code highlighting style. */
+[data-bs-theme="dark"] {
+ --dropdown-label-bg: var(--primary-800);
+ --right-side-bg: var(--surfaces-bg03);
+ --text-code-string: #95c2e7;
+ --text-code-keyword: #f4766e;
+ --text-code-meta: #c8ace1;
+ --text-code-type: #f69d50;
+ --text-code-literal: #6bb5fd;
+ --slider-rail-bg: var(--primary-100);
+ --collapse-icon-bg: var(--primary-500);
+}
+
+[data-bs-theme="light"] {
+ --dropdown-label-bg: var(--primary-300);
+ --right-side-bg: var(--surfaces-bg01);
+ --text-code-string: #0a3069;
+ --text-code-keyword: #d12d39;
+ --text-code-meta: #6f42c1;
+ --text-code-type: #f69d50;
+ --text-code-literal: #005cc5;
+ --fill-icon-image-card: invert(64%) sepia(0%) saturate(1375%);
+ --slider-rail-bg: var(--primary-900);
+ --collapse-icon-bg: var(--primary-300);
+}
+
+/* CARDS */
.card .nav-link {
height: 100%;
}
@@ -9,6 +37,7 @@ but do not want to take over to `vizro-bootstrap` as these settings might not be
margin-bottom: 0;
}
+/* ACCORDION */
.accordion-item .nav-link {
padding: 0.5rem 1rem;
}
@@ -16,3 +45,29 @@ but do not want to take over to `vizro-bootstrap` as these settings might not be
.accordion-item .nav-link.active {
border-left: 2px solid var(--border-enabled);
}
+
+/* TABS */
+.nav-tabs {
+ margin-bottom: 1.25rem;
+}
+
+.tab-content {
+ height: calc(100% - 3.25rem); /* 3.25rem: nav-tabs margin + height */
+}
+
+/* The dbc component adds an additional div element to which we cannot assign a className.
+To ensure the dynamic height adjustment and prevent scrolling, the height must be specified for that div as below. */
+.tab-pane,
+.tab-pane > div:first-child {
+ height: 100%;
+}
+
+/* Hides title of the first container given the title is already reflected in the tab title */
+.tab-content .container-title:first-of-type {
+ display: none;
+}
+
+/* Remove label that automatically gets added when calling `dbc.Switch` to remove gap. */
+label[for="theme-selector"] {
+ display: none;
+}
diff --git a/vizro-core/src/vizro/static/css/container.css b/vizro-core/src/vizro/static/css/container.css
deleted file mode 100644
index 6fe15633f..000000000
--- a/vizro-core/src/vizro/static/css/container.css
+++ /dev/null
@@ -1,5 +0,0 @@
-.page-component-container {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
diff --git a/vizro-core/src/vizro/static/css/datepicker.css b/vizro-core/src/vizro/static/css/datepicker.css
index b2d4a4ebb..3e167d5d0 100644
--- a/vizro-core/src/vizro/static/css/datepicker.css
+++ b/vizro-core/src/vizro/static/css/datepicker.css
@@ -1,6 +1,6 @@
.datepicker .mantine-Input-wrapper {
font-family: unset;
- height: var(--spacing-08);
+ height: 2rem;
}
.datepicker .mantine-DateRangePicker-input,
@@ -8,13 +8,13 @@
background-color: var(--field-enabled);
border: none;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
+ box-shadow: var(--elevation-0);
color: var(--text-secondary);
- font-size: var(--text-size-02);
- height: var(--spacing-08);
- line-height: var(--spacing-04);
- min-height: var(--spacing-08);
- padding: 0 var(--spacing-02);
+ font-size: 0.875rem;
+ height: 2rem;
+ line-height: 1rem;
+ min-height: 2rem;
+ padding: 0 0.5rem;
}
.datepicker .mantine-DateRangePicker-input:hover,
@@ -27,8 +27,8 @@
background: var(--field-enabled);
border: none;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-1);
- padding: var(--spacing-04) 11px; /* 11px otherwise not aligned with controls */
+ box-shadow: var(--elevation-1);
+ padding: 1rem 11px; /* 11px otherwise not aligned with controls */
}
.datepicker .mantine-UnstyledButton-root {
@@ -39,7 +39,7 @@
}
.datepicker .mantine-UnstyledButton-root:hover {
- background: var(--state-overlays-hover);
+ background: var(--stateOverlays-hover);
color: var(--text-primary);
}
@@ -47,7 +47,7 @@
.datepicker .mantine-DatePicker-weekday {
color: var(--text-secondary);
font-family: unset;
- padding: var(--spacing-02);
+ padding: 0.5rem;
}
.datepicker .mantine-DateRangePicker-cell,
@@ -75,7 +75,7 @@
.datepicker .mantine-DateRangePicker-day:focus-visible,
.datepicker .mantine-DatePicker-day:hover,
.datepicker .mantine-DatePicker-day:focus-visible {
- background: var(--state-overlays-hover);
+ background: var(--stateOverlays-hover);
border: none;
color: var(--text-primary);
outline: none;
@@ -83,7 +83,7 @@
}
.datepicker .mantine-DateRangePicker-day[data-in-range] {
- background: var(--state-overlays-selected);
+ background: var(--stateOverlays-selected);
color: var(--text-primary);
}
@@ -93,8 +93,8 @@
.datepicker .mantine-DatePicker-day[data-selected],
.datepicker .mantine-DatePicker-yearPickerControlActive,
.datepicker .mantine-DatePicker-monthPickerControlActive {
- background: var(--state-overlays-selected-inverse);
- color: var(--text-contrast-primary);
+ background: var(--stateOverlays-selected-inverted);
+ color: var(--text-primary-inverted);
text-decoration: underline;
}
diff --git a/vizro-core/src/vizro/static/css/dropdown.css b/vizro-core/src/vizro/static/css/dropdown.css
index 25d8ef943..1b5b01cad 100644
--- a/vizro-core/src/vizro/static/css/dropdown.css
+++ b/vizro-core/src/vizro/static/css/dropdown.css
@@ -3,8 +3,8 @@
background-color: var(--field-enabled);
border: none;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
- font-size: var(--text-size-02);
+ box-shadow: var(--elevation-0);
+ font-size: 0.875rem;
}
/* Dropdown menu when clicking on expand arrow */
@@ -12,20 +12,20 @@
background-color: var(--field-enabled);
border: none;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
- font-size: var(--text-size-02);
- line-height: var(--text-size-05);
+ box-shadow: var(--elevation-0);
+ font-size: 0.875rem;
+ line-height: 1.5rem;
}
/* Dropdown menu options */
#dashboard-container .VirtualizedSelectOption {
color: var(--text-primary);
- font-weight: var(--text-weight-regular);
+ font-weight: 400;
}
/* Dropdown menu hover effect */
#dashboard-container .VirtualizedSelectFocusedOption {
- background-color: var(--state-overlays-hover);
+ background-color: var(--stateOverlays-hover);
}
/* Input box for existing values and user input */
@@ -43,7 +43,7 @@
/* User input */
#dashboard-container .dash-dropdown .Select-input {
display: block;
- height: var(--tag-height);
+ height: 24px;
margin-left: unset;
}
@@ -58,12 +58,12 @@
/* Border on focus */
#dashboard-container .is-focused:not(.is-open) > .Select-control {
- box-shadow: 0 0 0 2px var(--focus-focus) inset;
+ box-shadow: 0 0 0 2px var(--focus) inset;
}
/* Single-select dropdown only ------------------- */
#dashboard-container .Select--single .Select-value {
- padding-left: var(--spacing-02);
+ padding-left: 0.5rem;
}
.has-value.Select--single > .Select-control .Select-value .Select-value-label,
@@ -78,24 +78,23 @@
/* Tags --------------------------- */
#dashboard-container .Select--multi .Select-value {
- background-color: var(--tags-bg-color);
+ background-color: var(--dropdown-label-bg);
border: 0;
border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
- color: var(--tags-text-color);
- font-size: var(--text-size-02);
- height: var(--tag-height);
+ box-shadow: var(--elevation-0);
+ color: var(--text-secondary);
+ font-size: 0.875rem;
height: 100%;
- letter-spacing: var(--letter-spacing-body-ui-02);
+ letter-spacing: -0.112px;
margin: 0;
- padding: 0 var(--spacing-01);
+ padding: 0 0.25rem;
vertical-align: baseline;
}
/* Tag: Label */
#dashboard-container .Select--multi .Select-value-label {
color: var(--text-primary);
- line-height: var(--text-size-05);
+ line-height: 1.5rem;
padding: 0 4px;
}
diff --git a/vizro-core/src/vizro/static/css/images.css b/vizro-core/src/vizro/static/css/images.css
deleted file mode 100644
index df3e4a4d0..000000000
--- a/vizro-core/src/vizro/static/css/images.css
+++ /dev/null
@@ -1,21 +0,0 @@
-img[src*="floating-right"] {
- float: right;
-}
-
-img[src*="floating-left"] {
- float: left;
-}
-
-img[src*="floating-center"] {
- display: block;
- float: none;
- height: auto;
- margin: auto;
- max-width: 100%;
-}
-
-img[src*="icon-top"] {
- filter: var(--fill-icon-image-card);
- height: 36px;
- width: 36px;
-}
diff --git a/vizro-core/src/vizro/static/css/layout.css b/vizro-core/src/vizro/static/css/layout.css
index f20e6dddd..a7c66f864 100644
--- a/vizro-core/src/vizro/static/css/layout.css
+++ b/vizro-core/src/vizro/static/css/layout.css
@@ -10,24 +10,24 @@
display: flex;
flex: 0 0 auto;
flex-direction: column;
- gap: var(--spacing-06);
+ gap: 1.5rem;
overflow: auto;
padding: 24px 24px 0;
width: 324px;
}
#left-side {
- background-color: var(--surfaces-bg-02);
+ background-color: var(--surfaces-bg02);
display: flex;
flex-direction: row;
height: 100%;
}
#right-side {
- background: var(--main-container-bg-color);
+ background: var(--right-side-bg);
display: flex;
flex-direction: column;
- gap: var(--spacing-05);
+ gap: 1.25rem;
padding: 24px;
width: 100%;
}
@@ -42,7 +42,7 @@
#page-header {
align-items: center;
- background-color: var(--surfaces-bg-02);
+ background-color: var(--surfaces-bg02);
display: flex;
flex-direction: row;
height: 60px;
@@ -53,12 +53,12 @@
}
#page-header:not(:empty) {
- border-bottom: 1px solid var(--border-subtle-alpha-01);
+ border-bottom: 1px solid var(--border-subtleAlpha01);
}
#page-components {
overflow: auto;
- padding-top: var(--spacing-01);
+ padding-top: 0.25rem;
}
.grid-layout {
@@ -76,38 +76,13 @@
align-self: stretch;
display: flex;
flex-direction: column;
- gap: var(--spacing-06);
- padding-bottom: var(--spacing-06);
- padding-top: var(--spacing-02);
+ gap: 1.5rem;
+ padding-bottom: 1.5rem;
+ padding-top: 0.5rem;
}
#control-panel:not(:empty) {
- border-bottom: 1px solid var(--border-subtle-alpha-01);
-}
-
-.page-error-container {
- align-items: center;
- display: flex;
- flex-direction: column;
- height: 100vh;
- justify-content: center;
- width: 100vw;
-}
-
-.error-content-container {
- align-items: center;
- display: inline-flex;
- flex-direction: column;
- gap: 24px;
- margin-top: -32px;
-}
-
-.error-text-container {
- display: flex;
- flex-direction: column;
- gap: 8px;
- text-align: center;
- width: 336px;
+ border-bottom: 1px solid var(--border-subtleAlpha01);
}
.dashboard_title {
@@ -125,7 +100,7 @@
}
#left-sidebar {
- border-right: 1px solid var(--border-subtle-alpha-01);
+ border-right: 1px solid var(--border-subtleAlpha01);
display: flex;
flex-direction: column;
gap: 40px;
@@ -177,7 +152,7 @@
}
#collapse-icon.material-symbols-outlined {
- background-color: var(--tooltip-bg-color);
+ background-color: var(--collapse-icon-bg);
border-radius: 50%;
color: var(--text-disabled);
cursor: pointer;
@@ -185,7 +160,7 @@
}
#collapse-icon.material-symbols-outlined:hover {
- color: var(--text-active);
+ color: var(--text-primary);
}
.collapse-icon-div {
@@ -195,6 +170,12 @@
width: 0;
}
+.page-component-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
/* Note: This is only meant as a quick-fix to improve some of the mobile layouts. */
/* Long-term wise this should be replaced by refactoring our CSS code and components to be mobile-compatible. */
diff --git a/vizro-core/src/vizro/static/css/scroll_bar.css b/vizro-core/src/vizro/static/css/scroll_bar.css
index 3c9dc34af..43381bfa6 100644
--- a/vizro-core/src/vizro/static/css/scroll_bar.css
+++ b/vizro-core/src/vizro/static/css/scroll_bar.css
@@ -9,11 +9,11 @@
}
::-webkit-scrollbar-thumb:hover {
- background: var(--fill-medium-emphasis);
+ background: var(--fill-secondary);
}
#left-main::-webkit-scrollbar-thumb {
- border-color: var(--surfaces-bg-02);
+ border-color: var(--surfaces-bg02);
}
.card::-webkit-scrollbar-thumb,
@@ -23,11 +23,11 @@
}
#page-components::-webkit-scrollbar-thumb {
- border-color: var(--main-container-bg-color);
+ border-color: var(--right-side-bg);
}
.table-container::-webkit-scrollbar-thumb {
- border-color: var(--main-container-bg-color);
+ border-color: var(--right-side-bg);
}
/* Can't control thumb color so hover is turned off */
diff --git a/vizro-core/src/vizro/static/css/slider.css b/vizro-core/src/vizro/static/css/slider.css
index c3e936efc..db27caf43 100644
--- a/vizro-core/src/vizro/static/css/slider.css
+++ b/vizro-core/src/vizro/static/css/slider.css
@@ -5,16 +5,16 @@
.rc-slider-rail,
.rc-slider-track {
- background-color: var(--slider-background-color);
+ background-color: var(--slider-rail-bg);
height: 2px;
}
.rc-slider-track {
- background-color: var(--fill-on-active);
+ background-color: var(--fill-active);
}
.rc-slider-dot {
- background-color: var(--slider-background-color);
+ background-color: var(--slider-rail-bg);
border: var(--field-enabled);
bottom: 0;
height: 6px;
@@ -22,16 +22,16 @@
}
.rc-slider-dot-active {
- background-color: var(--fill-on-active);
+ background-color: var(--fill-active);
}
.rc-slider-handle,
.rc-slider-handle:hover,
.rc-slider-handle-dragging.rc-slider-handle-dragging.rc-slider-handle-dragging,
.rc-slider-handle-click-focused:focus {
- background-color: var(--surfaces-bg-01);
- border: solid 6px var(--fill-on-active);
- border-color: var(--fill-on-active);
+ background-color: var(--surfaces-bg01);
+ border: solid 6px var(--fill-active);
+ border-color: var(--fill-active);
border-radius: 100%;
height: 16px;
margin: -8px 0 0;
@@ -41,7 +41,7 @@
.rc-slider-handle:hover,
.rc-slider-handle-dragging.rc-slider-handle-dragging.rc-slider-handle-dragging {
- border: solid 4px var(--fill-on-active);
+ border: solid 4px var(--fill-active);
box-shadow: unset;
cursor: context-menu;
}
@@ -51,7 +51,7 @@
}
.rc-slider-handle:active {
- border: solid 6px var(--fill-on-active);
+ border: solid 6px var(--fill-active);
box-shadow: unset;
cursor: grabbing;
height: 16px;
@@ -61,14 +61,14 @@
.rc-slider-mark-text {
color: var(--text-secondary);
- font-size: var(--text-size-01);
- line-height: var(--text-size-02);
- margin-top: var(--spacing-01);
+ font-size: 0.75rem;
+ line-height: 0.875rem;
+ margin-top: 0.25rem;
min-width: 44px;
}
.rc-slider-mark-text-active {
- color: var(--fill-on-active);
+ color: var(--fill-active);
}
.slider-track-with-marks,
@@ -96,7 +96,7 @@ input.dash-input:invalid {
display: flex;
flex-direction: row;
justify-content: space-between;
- line-height: var(--text-size-03);
+ line-height: 1rem;
}
.slider-label-input label {
@@ -107,24 +107,24 @@ input.dash-input:invalid {
.slider-text-input-container {
display: flex;
flex-direction: row;
- gap: var(--spacing-01);
- margin-bottom: var(--spacing-03);
+ gap: 0.25rem;
+ margin-bottom: 0.75rem;
}
.slider-text-input-field {
background-color: transparent;
color: var(--text-secondary);
- font-size: var(--text-size-02);
+ font-size: 0.875rem;
max-width: 80px; /* required for Mozilla */
padding: 0;
text-align: center;
text-decoration: underline;
- text-decoration-color: var(--border-subtle-alpha-01);
+ text-decoration-color: var(--border-subtleAlpha01);
}
.slider-text-input-range-separator {
color: var(--text-secondary);
- font-size: var(--text-size-02);
+ font-size: 0.875rem;
}
/* To remove number input spin box */
diff --git a/vizro-core/src/vizro/static/css/table.css b/vizro-core/src/vizro/static/css/table.css
index a1fb896f6..e6e876496 100644
--- a/vizro-core/src/vizro/static/css/table.css
+++ b/vizro-core/src/vizro/static/css/table.css
@@ -11,7 +11,7 @@
.dash-spreadsheet-container
.dash-spreadsheet-inner
th {
- background-color: var(--main-container-bg-color);
+ background-color: var(--right-side-bg);
color: var(--text-primary);
padding: 10px 0;
}
@@ -21,7 +21,7 @@
.dash-spreadsheet-container
.dash-spreadsheet-inner
td {
- background-color: var(--main-container-bg-color);
+ background-color: var(--right-side-bg);
color: var(--text-primary);
}
@@ -30,7 +30,7 @@
.dash-spreadsheet-container
.dash-spreadsheet-inner
table {
- --hover: var(--main-container-bg-color);
+ --hover: var(--right-side-bg);
width: 100%;
}
diff --git a/vizro-core/src/vizro/static/css/tabs.css b/vizro-core/src/vizro/static/css/tabs.css
deleted file mode 100644
index 2e49d1c21..000000000
--- a/vizro-core/src/vizro/static/css/tabs.css
+++ /dev/null
@@ -1,59 +0,0 @@
-.tabs {
- display: flex;
- flex-direction: column;
- gap: 20px;
- height: 100%;
-}
-
-.tabs-list {
- align-items: flex-start;
- align-self: stretch;
- border-bottom: 1px solid var(--border-subtle-alpha-01);
- display: flex;
- flex-wrap: nowrap;
- gap: 16px;
- height: 32px;
-}
-
-.tabs-panel {
- height: calc(100% - 60px);
-}
-
-.tab-content {
- height: 100%;
-}
-
-.tab-title {
- align-items: flex-start;
- border-bottom: 1px solid transparent;
- color: var(--text-secondary);
- display: flex;
- font-size: 16px;
- height: 32px;
- line-height: 20px;
- margin: 0;
- padding: 0;
-}
-
-.tab-title:hover {
- background-color: transparent;
- border-bottom: 1px solid var(--text-active);
-}
-
-.tab-title[data-active] {
- border-bottom: 1px solid var(--text-active);
- color: var(--text-active);
-}
-
-.tab-title[data-active]:hover {
- background-color: transparent;
- border-color: 1px solid var(--text-active);
-}
-
-.tab-title[data-active] .mantine-Tabs-tabLabel {
- color: var(--text-active);
-}
-
-.tab-content > .page-component-container > .container-title {
- display: none;
-}
diff --git a/vizro-core/src/vizro/static/css/toggle.css b/vizro-core/src/vizro/static/css/toggle.css
deleted file mode 100644
index 5158e4c16..000000000
--- a/vizro-core/src/vizro/static/css/toggle.css
+++ /dev/null
@@ -1,43 +0,0 @@
-.toggle-switch {
- width: 32px;
-}
-
-#dashboard-container .mantine-Switch-track {
- background-color: var(--fill-subtle);
- border: 1px solid var(--border-enabled);
- border-radius: 16px;
- height: 16px;
- min-width: 32px;
- width: 32px;
-}
-
-#dashboard-container .mantine-Switch-track:focus {
- border: 2px solid var(--focus-focus);
-}
-
-#dashboard-container .mantine-Switch-input {
- margin: 0;
-}
-
-#dashboard-container .mantine-Switch-trackLabel {
- height: 16px;
- margin: 0;
- width: 32px;
-}
-
-#dashboard-container .mantine-Switch-thumb {
- background-color: var(--fill-medium-emphasis);
- border: none;
- height: 10px;
- width: 10px;
-}
-
-#dashboard-container input:checked + * > .mantine-11dx59s {
- background: var(--text-contrast-primary);
- left: calc(100% - 12px);
-}
-
-#dashboard-container input:checked + * > .mantine-69c9zd {
- background: var(--text-primary);
- border-color: var(--border-enabled);
-}
diff --git a/vizro-core/src/vizro/static/css/token_names.css b/vizro-core/src/vizro/static/css/token_names.css
deleted file mode 100644
index 589269228..000000000
--- a/vizro-core/src/vizro/static/css/token_names.css
+++ /dev/null
@@ -1,89 +0,0 @@
-:root {
- --primary-dark-100: #333640;
- --primary-dark-200: #2f323c;
- --primary-dark-300: #2b2e39;
- --primary-dark-400: #272a35;
- --primary-dark-500: #232632;
- --primary-dark-600: #1f222e;
- --primary-dark-700: #1b1e2a;
- --primary-dark-800: #181b26;
- --primary-dark-900: #141721;
- --fill-dark-mode-active: rgba(255, 255, 255, 0.88);
- --surfaces-dark-mode-bg-01: rgba(35, 38, 50, 1);
- --surfaces-dark-mode-bg-02: rgba(27, 30, 42, 1);
- --surfaces-dark-mode-bg-03: rgba(20, 23, 33, 1);
- --surfaces-dark-mode-bg-card: rgba(35, 38, 50, 1);
- --border-dark-mode-disabled: rgba(255, 255, 255, 0.3);
- --field-dark-mode-disabled: rgba(240, 241, 242, 1);
- --fill-dark-mode-disabled: rgba(255, 255, 255, 0.3);
- --text-dark-mode-disabled: rgba(255, 255, 255, 0.3);
- --border-dark-mode-enabled: rgba(255, 255, 255, 0.6);
- --field-dark-mode-enabled: rgba(43, 46, 57, 1);
- --status-dark-mode-error: rgba(245, 101, 101, 1);
- --border-dark-mode-hover: rgba(255, 255, 255, 0.88);
- --field-dark-mode-hover: rgba(55, 58, 68, 1);
- --fill-dark-mode-hover-selected: rgba(255, 255, 255, 1);
- --status-dark-mode-information: rgba(0, 180, 255, 1);
- --fill-dark-mode-medium-emphasis: rgba(255, 255, 255, 0.6);
- --text-dark-mode-placeholder: rgba(255, 255, 255, 0.38);
- --text-dark-mode-primary: rgba(255, 255, 255, 0.88);
- --text-dark-mode-secondary: rgba(255, 255, 255, 0.6);
- --border-dark-mode-selected: #ffffff;
- --fill-dark-mode-subtle: rgba(255, 255, 255, 0.1);
- --border-dark-mode-subtle-alpha-01: rgba(255, 255, 255, 0.1);
- --border-dark-mode-subtle-alpha-02: rgba(255, 255, 255, 0.16);
- --status-dark-mode-success: rgba(64, 216, 110, 1);
- --tags-dark-mode-text-color: rgba(255, 255, 255, 0.6);
- --status-dark-mode-warning: rgba(255, 193, 7, 1);
- --primary-light-100: #fafafb;
- --primary-light-200: #f5f6f6;
- --primary-light-300: #f2f3f4;
- --primary-light-400: #ebedee;
- --primary-light-50: #ffffff;
- --primary-light-500: #e6e8ea;
- --primary-light-600: #e2e4e6;
- --primary-light-700: #dddfe1;
- --primary-light-800: #d8dadd;
- --primary-light-900: #d3d6d9;
- --fill-light-mode-active: rgba(20, 23, 33, 0.88);
- --surfaces-light-mode-bg-01: rgba(255, 255, 255, 1);
- --surfaces-light-mode-bg-02: rgba(245, 246, 246, 1);
- --surfaces-light-mode-bg-03: rgba(230, 232, 234, 1);
- --surfaces-light-mode-bg-card: rgba(245, 246, 246, 1);
- --border-light-mode-disabled: rgba(20, 23, 33, 0.3);
- --field-light-mode-disabled: rgba(240, 241, 242, 1);
- --fill-light-mode-disabled: rgba(20, 23, 33, 0.3);
- --text-light-mode-disabled: rgba(20, 23, 33, 0.3);
- --border-light-mode-enabled: rgba(20, 23, 33, 0.6);
- --field-light-mode-enabled: rgba(250, 250, 251, 1);
- --status-light-mode-error: rgba(240, 59, 58, 1);
- --border-light-mode-hover: rgba(20, 23, 33, 0.88);
- --field-light-mode-hover: rgba(255, 255, 255, 1);
- --fill-light-mode-hover-selected: rgba(20, 23, 33, 1);
- --status-light-mode-information: rgba(0, 158, 255, 1);
- --fill-light-mode-medium-emphasis: rgba(20, 23, 33, 0.6);
- --text-light-mode-placeholder: rgba(20, 23, 33, 0.38);
- --text-light-mode-primary: rgba(20, 23, 33, 0.88);
- --text-light-mode-secondary: rgba(20, 23, 33, 0.6);
- --border-light-mode-selected: #141721;
- --fill-light-mode-subtle: rgba(0, 0, 0, 0.1);
- --border-light-mode-subtle-alpha-01: rgba(20, 23, 33, 0.1);
- --border-light-mode-subtle-alpha-02: rgba(20, 23, 33, 0.16);
- --status-light-mode-success: rgba(38, 191, 86, 1);
- --tags-light-mode-text-color: rgba(255, 255, 255, 0.6);
- --status-light-mode-warning: rgba(241, 124, 2, 1);
- --overlays-on-light-ui-high-contrast: rgba(239, 240, 248, 0.88);
- --overlays-on-light-ui-medium-contrast: rgba(239, 240, 248, 0.6);
- --state-overlays-dark-mode-active: rgba(255, 255, 255, 0.08);
- --state-overlays-dark-mode-enable: rgba(255, 255, 255, 0);
- --state-overlays-dark-mode-hover: rgba(255, 255, 255, 0.04);
- --state-overlays-dark-mode-selected: rgba(255, 255, 255, 0.1);
- --state-overlays-dark-mode-selected-inverse: #ffffff;
- --state-overlays-dark-mode-selected-hover: rgba(255, 255, 255, 0.16);
- --state-overlays-light-mode-active: rgba(20, 23, 33, 0.12);
- --state-overlays-light-mode-enable: rgba(20, 23, 33, 0);
- --state-overlays-light-mode-hover: rgba(20, 23, 33, 0.06);
- --state-overlays-light-mode-selected: rgba(20, 23, 33, 0.08);
- --state-overlays-light-mode-selected-inverse: #141721;
- --state-overlays-light-mode-selected-hover: rgba(20, 23, 33, 0.24);
-}
diff --git a/vizro-core/src/vizro/static/css/tooltip.css b/vizro-core/src/vizro/static/css/tooltip.css
deleted file mode 100644
index 478b879a3..000000000
--- a/vizro-core/src/vizro/static/css/tooltip.css
+++ /dev/null
@@ -1,25 +0,0 @@
-.tooltip-inner {
- border-radius: 0;
- box-shadow: var(--box-shadow-elevation-0);
- filter: drop-shadow(0 2px 2px #141721);
- font-size: var(--text-size-01);
- font-weight: var(--text-weight-light);
- letter-spacing: var(--letter-spacing-help-text);
- line-height: var(--text-size-03);
- max-width: 180px;
- overflow-wrap: break-word;
- padding: var(--spacing-01) var(--spacing-02);
- white-space: pre-wrap;
-}
-
-.bs-tooltip-end .tooltip-arrow::before {
- right: -3px;
-}
-
-.tooltip.show {
- opacity: 1;
-}
-
-.tooltip {
- pointer-events: none;
-}
diff --git a/vizro-core/src/vizro/static/css/variables.css b/vizro-core/src/vizro/static/css/variables.css
deleted file mode 100644
index 20ebc078c..000000000
--- a/vizro-core/src/vizro/static/css/variables.css
+++ /dev/null
@@ -1,167 +0,0 @@
-/* Add variables here that are the same in dark and light */
-:root {
- --spacing-01: 4px;
- --spacing-02: 8px;
- --spacing-03: 12px;
- --spacing-04: 16px;
- --spacing-05: 20px;
- --spacing-06: 24px;
- --spacing-07: 28px;
- --spacing-08: 32px;
- --tag-height: 24px;
- --text-size-01: 12px;
- --text-size-02: 14px;
- --text-size-03: 16px;
- --text-size-04: 20px;
- --text-size-05: 24px;
- --text-size-06: 28px;
- --text-size-07: 32px;
- --letter-spacing-body-edit-01: -0.032px;
- --letter-spacing-body-edit-02: -0.028px;
- --letter-spacing-body-link-02: -0.056px;
- --letter-spacing-body-ui-01: -0.128px;
- --letter-spacing-body-ui-02: -0.112px;
- --letter-spacing-heading-h1: -0.096px;
- --letter-spacing-heading-h4: -0.016px;
- --letter-spacing-help-text: 0.024px;
- --text-weight-light: 300;
- --text-weight-regular: 400;
- --text-weight-semibold: 600;
-}
-
-/* Ensure dark and light have same list of variables (only color variables) */
-[data-bs-theme="dark"] {
- --fill-active: var(--fill-dark-mode-active);
- --text-active: rgba(255, 255, 255, 1);
- --slider-background-color: #373a44;
- --surfaces-bg-01: var(--surfaces-dark-mode-bg-01);
- --surfaces-bg-02: var(--surfaces-dark-mode-bg-02);
- --surfaces-bg-03: var(--surfaces-dark-mode-bg-03);
- --surfaces-bg-card: var(--surfaces-dark-mode-bg-card);
- --tags-bg-color: #181b26;
- --tooltip-bg-color: var(--primary-dark-500);
- --main-container-bg-color: rgba(20, 23, 33, 1);
- --fill-contrast-hover-selected: rgba(20, 23, 33, 1);
- --text-contrast-primary: rgba(20, 23, 33, 0.88);
- --border-contrast-selected: rgba(20, 23, 33, 1);
- --border-disabled: var(--border-dark-mode-disabled);
- --field-disabled: var(--field-dark-mode-disabled);
- --text-disabled: var(--text-dark-mode-disabled);
- --border-enabled: var(--border-dark-mode-enabled);
- --field-enabled: var(--field-dark-mode-enabled);
- --status-error: var(--status-dark-mode-error);
- --focus-focus: rgba(0, 133, 255, 0.6);
- --status-focus: rgba(0, 133, 255, 0.6);
- --background-hover: rgba(255, 255, 255, 0.08);
- --border-hover: var(--border-dark-mode-hover);
- --field-hover: var(--field-dark-mode-hover);
- --fill-hover-selected: var(--fill-dark-mode-hover-selected);
- --status-information: var(--status-dark-mode-information);
- --fill-medium-emphasis: var(--fill-dark-mode-medium-emphasis);
- --fill-on-active: rgba(255, 255, 255, 1);
- --state-overlays-active: var(--state-overlays-dark-mode-active);
- --state-overlays-contrast-hover: var(--state-overlays-light-mode-hover);
- --state-overlays-enable: var(--state-overlays-dark-mode-enable);
- --state-overlays-hover: var(--state-overlays-dark-mode-hover);
- --state-overlays-selected: var(--state-overlays-dark-mode-selected);
- --state-overlays-selected-inverse: var(
- --state-overlays-dark-mode-selected-inverse
- );
- --state-overlays-selected-hover: var(
- --state-overlays-dark-mode-selected-hover
- );
- --text-placeholder: var(--text-dark-mode-placeholder);
- --text-primary: var(--text-dark-mode-primary);
- --text-secondary: var(--text-dark-mode-secondary);
- --background-selected: rgba(0, 0, 0, 0.12);
- --border-selected: var(--border-dark-mode-selected);
- --box-shadow-elevation-0: 0px 1px 1px 0px rgba(20, 23, 33, 0.12),
- 0px 0px 1px 1px rgba(20, 23, 33, 0.08);
- --box-shadow-elevation-1: 0px 2px 4px -1px rgba(20, 23, 33, 0.38),
- 0px 1px 2px -1px rgba(20, 23, 33, 0.88);
- --box-shadow-elevation-card: 0px 2px 2px -1px rgba(20, 23, 33, 0.38),
- 0px 2px 6px -1px rgba(20, 23, 33, 0.16);
- --box-shadow-elevation-card-hover: 0px 2px 2px 0px rgba(20, 23, 33, 0.24),
- 0px 4px 8px 1px rgba(20, 23, 33, 0.12);
- --fill-subtle: var(--fill-dark-mode-subtle);
- --border-subtle-alpha-01: var(--border-dark-mode-subtle-alpha-01);
- --border-subtle-alpha-02: var(--border-dark-mode-subtle-alpha-02);
- --status-success: var(--status-dark-mode-success);
- --tags-text-color: var(--tags-dark-mode-text-color);
- --status-warning: var(--status-dark-mode-warning);
- --text-code-string: #95c2e7;
- --text-code-keyword: #f4766e;
- --text-code-meta: #c8ace1;
- --text-code-type: #f69d50;
- --text-code-literal: #6bb5fd;
-}
-
-[data-bs-theme="light"] {
- --fill-accordion-button: invert(64%) sepia(0%) saturate(1375%);
- --fill-active: var(--fill-light-mode-active);
- --text-active: rgba(20, 23, 33, 1);
- --slider-background-color: #d3d6d9;
- --surfaces-bg-01: var(--surfaces-light-mode-bg-01);
- --surfaces-bg-02: var(--surfaces-light-mode-bg-02);
- --surfaces-bg-03: var(--surfaces-light-mode-bg-03);
- --surfaces-bg-card: var(--surfaces-light-mode-bg-card);
- --tags-bg-color: var(--primary-light-300);
- --tooltip-bg-color: var(--primary-light-100);
- --main-container-bg-color: rgba(255, 255, 255, 1);
- --fill-contrast-hover-selected: rgba(255, 255, 255, 1);
- --text-contrast-primary: rgba(255, 255, 255, 0.88);
- --border-contrast-selected: rgba(255, 255, 255, 1);
- --border-disabled: var(--border-light-mode-disabled);
- --field-disabled: var(--field-light-mode-disabled);
- --text-disabled: var(--text-light-mode-disabled);
- --border-enabled: var(--border-light-mode-enabled);
- --field-enabled: var(--field-light-mode-enabled);
- --status-error: var(--status-light-mode-error);
- --focus-focus: rgba(0, 133, 255, 0.6);
- --status-focus: rgba(0, 133, 255, 0.6);
- --background-hover: var(--overlays-on-light-ui-medium-contrast);
- --border-hover: var(--border-light-mode-hover);
- --field-hover: var(--field-light-mode-hover);
- --fill-hover-selected: var(--fill-light-mode-hover-selected);
- --fill-icon-image-card: invert(64%) sepia(0%) saturate(1375%)
- hue-rotate(247deg) brightness(95%) contrast(90%);
- --status-information: var(--status-light-mode-information);
- --fill-medium-emphasis: var(--fill-light-mode-medium-emphasis);
- --fill-on-active: rgba(0, 0, 0, 1);
- --state-overlays-active: var(--state-overlays-light-mode-active);
- --state-overlays-contrast-hover: var(--state-overlays-dark-mode-hover);
- --state-overlays-enable: var(--state-overlays-light-mode-enable);
- --state-overlays-hover: var(--state-overlays-light-mode-hover);
- --state-overlays-selected: var(--state-overlays-light-mode-selected);
- --state-overlays-selected-inverse: var(
- --state-overlays-light-mode-selected-inverse
- );
- --state-overlays-selected-hover: var(
- --state-overlays-light-mode-selected-hover
- );
- --text-placeholder: var(--text-light-mode-placeholder);
- --text-primary: var(--text-light-mode-primary);
- --text-secondary: var(--text-light-mode-secondary);
- --background-selected: var(--overlays-on-light-ui-high-contrast);
- --border-selected: var(--border-light-mode-selected);
- --box-shadow-elevation-0: 0px 1px 1px 0px rgba(20, 23, 33, 0.12),
- 0px 0px 1px 1px rgba(20, 23, 33, 0.08);
- --box-shadow-elevation-1: 0px 2px 4px -1px rgba(20, 23, 33, 0.12),
- 0px 1px 2px -1px rgba(20, 23, 33, 0.08);
- --box-shadow-elevation-card: 0px 1px 1px 0px rgba(20, 23, 33, 0.08),
- 0px 0px 1px 0px rgba(20, 23, 33, 0.38);
- --box-shadow-elevation-card-hover: 0px 2px 2px 0px rgba(20, 23, 33, 0.24),
- 0px 4px 8px 1px rgba(20, 23, 33, 0.12);
- --fill-subtle: var(--fill-light-mode-subtle);
- --border-subtle-alpha-01: var(--border-light-mode-subtle-alpha-01);
- --border-subtle-alpha-02: var(--border-light-mode-subtle-alpha-02);
- --status-success: var(--status-light-mode-success);
- --tags-text-color: var(--tags-light-mode-text-color);
- --status-warning: var(--status-light-mode-warning);
- --inverse-color: invert(100%);
- --text-code-string: #0a3069;
- --text-code-keyword: #d12d39;
- --text-code-meta: #6f42c1;
- --text-code-type: #f69d50;
- --text-code-literal: #005cc5;
-}
diff --git a/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css b/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css
index 490a9dbbf..83c26bc15 100644
--- a/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css
+++ b/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css
@@ -2,4 +2,4 @@
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- */:root,[data-bs-theme=light]{--bs-blue: #1a85ff;--bs-indigo: #6610f2;--bs-purple: #976fd1;--bs-pink: #d41159;--bs-red: #ff5267;--bs-orange: #ff9222;--bs-yellow: #fdc935;--bs-green: #689f38;--bs-teal: #08bdba;--bs-cyan: #00b4ff;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-primary: #1a85ff;--bs-secondary: #6c757d;--bs-success: #689f38;--bs-info: #00b4ff;--bs-warning: #fdc935;--bs-danger: #ff5267;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-primary-rgb: 26, 133, 255;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 104, 159, 56;--bs-info-rgb: 0, 180, 255;--bs-warning-rgb: 253, 201, 53;--bs-danger-rgb: 255, 82, 103;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #0a3566;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #2a4016;--bs-info-text-emphasis: #004866;--bs-warning-text-emphasis: #655015;--bs-danger-text-emphasis: #662129;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #d1e7ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #e1ecd7;--bs-info-bg-subtle: #ccf0ff;--bs-warning-bg-subtle: #fff4d7;--bs-danger-bg-subtle: #ffdce1;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #a3ceff;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #c3d9af;--bs-info-border-subtle: #99e1ff;--bs-warning-border-subtle: #fee9ae;--bs-danger-border-subtle: #ffbac2;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: inter, sans-serif, arial, serif, "Segoe UI", roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size:0.875rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #1a85ff;--bs-link-color-rgb: 26, 133, 255;--bs-link-decoration: underline;--bs-link-hover-color: #156acc;--bs-link-hover-color-rgb: 21, 106, 204;--bs-code-color: #d41159;--bs-highlight-color: #212529;--bs-highlight-bg: #fff4d7;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0;--bs-border-radius-sm: 0;--bs-border-radius-lg: 0;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(26, 133, 255, 0.25);--bs-form-valid-color: #689f38;--bs-form-valid-border-color: #689f38;--bs-form-invalid-color: #ff5267;--bs-form-invalid-border-color: #ff5267}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #76b6ff;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #a4c588;--bs-info-text-emphasis: #66d2ff;--bs-warning-text-emphasis: #fedf86;--bs-danger-text-emphasis: #ff97a4;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #051b33;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #15200b;--bs-info-bg-subtle: #002433;--bs-warning-bg-subtle: #33280b;--bs-danger-bg-subtle: #331015;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #105099;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #3e5f22;--bs-info-border-subtle: #006c99;--bs-warning-border-subtle: #987920;--bs-danger-border-subtle: #99313e;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #76b6ff;--bs-link-hover-color: #91c5ff;--bs-link-color-rgb: 118, 182, 255;--bs-link-hover-color-rgb: 145, 197, 255;--bs-code-color: #e5709b;--bs-highlight-color: #dee2e6;--bs-highlight-bg: #655015;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #a4c588;--bs-form-valid-border-color: #a4c588;--bs-form-invalid-color: #ff97a4;--bs-form-invalid-border-color: #ff97a4}*,*::before,*::after{box-sizing:border-box}@media(prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.34375rem + 1.125vw)}@media(min-width: 1200px){h1,.h1{font-size:2.1875rem}}h2,.h2{font-size:calc(1.3rem + 0.6vw)}@media(min-width: 1200px){h2,.h2{font-size:1.75rem}}h3,.h3{font-size:calc(1.278125rem + 0.3375vw)}@media(min-width: 1200px){h3,.h3{font-size:1.53125rem}}h4,.h4{font-size:calc(1.25625rem + 0.075vw)}@media(min-width: 1200px){h4,.h4{font-size:1.3125rem}}h5,.h5{font-size:1.09375rem}h6,.h6{font-size:0.875rem}p{margin-top:0;margin-bottom:.5rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:0.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color)}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(--bs-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:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-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:1.09375rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.09375rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-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{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1*var(--bs-gutter-y));margin-right:calc(-0.5*var(--bs-gutter-x));margin-left:calc(-0.5*var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-0,.gy-0{--bs-gutter-y: 0}.g-1,.gx-1{--bs-gutter-x: 0.25rem}.g-1,.gy-1{--bs-gutter-y: 0.25rem}.g-2,.gx-2{--bs-gutter-x: 0.5rem}.g-2,.gy-2{--bs-gutter-y: 0.5rem}.g-3,.gx-3{--bs-gutter-x: 1rem}.g-3,.gy-3{--bs-gutter-y: 1rem}.g-4,.gx-4{--bs-gutter-x: 1.5rem}.g-4,.gy-4{--bs-gutter-y: 1.5rem}.g-5,.gx-5{--bs-gutter-x: 3rem}.g-5,.gy-5{--bs-gutter-y: 3rem}@media(min-width: 576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-sm-0,.gy-sm-0{--bs-gutter-y: 0}.g-sm-1,.gx-sm-1{--bs-gutter-x: 0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: 0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: 0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: 0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x: 3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y: 3rem}}@media(min-width: 768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-md-0,.gy-md-0{--bs-gutter-y: 0}.g-md-1,.gx-md-1{--bs-gutter-x: 0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y: 0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x: 0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y: 0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x: 1rem}.g-md-3,.gy-md-3{--bs-gutter-y: 1rem}.g-md-4,.gx-md-4{--bs-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x: 3rem}.g-md-5,.gy-md-5{--bs-gutter-y: 3rem}}@media(min-width: 992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-lg-0,.gy-lg-0{--bs-gutter-y: 0}.g-lg-1,.gx-lg-1{--bs-gutter-x: 0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: 0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: 0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: 0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x: 3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y: 3rem}}@media(min-width: 1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-xl-0,.gy-xl-0{--bs-gutter-y: 0}.g-xl-1,.gx-xl-1{--bs-gutter-x: 0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: 0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: 0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: 0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x: 3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y: 3rem}}@media(min-width: 1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x: 0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: 0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: 0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: 0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x: 3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y: 3rem}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-emphasis-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-emphasis-color);--bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color: var(--bs-emphasis-color);--bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color: var(--bs-emphasis-color);--bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width)*2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-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(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #d1e7ff;--bs-table-border-color: #a7b9cc;--bs-table-striped-bg: #c7dbf2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0e6;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #b5b6b7;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #e1ecd7;--bs-table-border-color: #b4bdac;--bs-table-striped-bg: #d6e0cc;--bs-table-striped-color: #000;--bs-table-active-bg: #cbd4c2;--bs-table-active-color: #000;--bs-table-hover-bg: #d0dac7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #ccf0ff;--bs-table-border-color: #a3c0cc;--bs-table-striped-bg: #c2e4f2;--bs-table-striped-color: #000;--bs-table-active-bg: #b8d8e6;--bs-table-active-color: #000;--bs-table-hover-bg: #bddeec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff4d7;--bs-table-border-color: #ccc3ac;--bs-table-striped-bg: #f2e8cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dcc2;--bs-table-active-color: #000;--bs-table-hover-bg: #ece2c7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #ffdce1;--bs-table-border-color: #ccb0b4;--bs-table-striped-bg: #f2d1d6;--bs-table-striped-color: #000;--bs-table-active-bg: #e6c6cb;--bs-table-active-color: #000;--bs-table-hover-bg: #ecccd0;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #c6c7c8;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: #4d5154;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #fff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #fff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-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}.col-form-label{padding-top:calc(0.25rem + var(--bs-border-width));padding-bottom:calc(0.25rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.6}.col-form-label-lg{padding-top:calc(0.5rem + var(--bs-border-width));padding-bottom:calc(0.5rem + var(--bs-border-width));font-size:0.875rem}.col-form-label-sm{padding-top:calc(0.25rem + var(--bs-border-width));padding-bottom:calc(0.25rem + var(--bs-border-width));font-size:0.65625rem}.form-text{margin-top:.25rem;font-size:0.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:0}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.6em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.25rem 0;margin-bottom:0;line-height:1.6;color:var(--bs-body-color);background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:var(--bs-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.6em + 0.5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:0.65625rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:0.875rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2));padding:.25rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important}.form-control-color::-webkit-color-swatch{border:0 !important}.form-control-color.form-control-sm{height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-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='%23343a40' 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:.25rem 1.5rem .25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .5rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:0}.form-select:focus{border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.5rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.65625rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:0.875rem}[data-bs-theme=dark] .form-select{--bs-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='%23dee2e6' 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.3125rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-check-input:checked{background-color:#1a85ff;border-color:#1a85ff}.form-check-input:checked[type=checkbox]{--bs-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='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#1a85ff;border-color:#1a85ff;--bs-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='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-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%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:0}.form-switch .form-check-input:focus{--bs-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='%238dc2ff'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-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='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:1}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,133,255,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,133,255,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;-webkit-appearance:none;appearance:none;background-color:#1a85ff;border:0}.form-range::-webkit-slider-thumb:active{background-color:#badaff}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#1a85ff;border:0}.form-range::-moz-range-thumb:active{background-color:#badaff}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-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(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .5rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid rgba(0,0,0,0);transform-origin:0 0}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .5rem}.form-floating>.form-control::-moz-placeholder, .form-floating>.form-control-plaintext::-moz-placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:not(:-moz-placeholder-shown), .form-floating>.form-control-plaintext:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.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:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem .25rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg)}.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 .25rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:var(--bs-secondary-bg)}.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:.25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:0.875rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.65625rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:2rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width)*-1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.65625rem;color:#fff;background-color:var(--bs-success)}.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(--bs-form-valid-border-color);padding-right:calc(1.6em + 0.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23689f38' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.4em + 0.125rem) center;background-size:calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.6em + 0.5rem);background-position:top calc(0.4em + 0.125rem) right calc(0.4em + 0.125rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--bs-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"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23689f38' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:2.75rem;background-position:right .5rem center,center right 1.5rem;background-size:16px 12px,calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.6em + 0.5rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--bs-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--bs-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:0.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.65625rem;color:#fff;background-color:var(--bs-danger)}.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(--bs-form-invalid-border-color);padding-right:calc(1.6em + 0.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff5267'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff5267' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.4em + 0.125rem) center;background-size:calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.6em + 0.5rem);background-position:top calc(0.4em + 0.125rem) right calc(0.4em + 0.125rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--bs-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"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff5267'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff5267' stroke='none'/%3e%3c/svg%3e");padding-right:2.75rem;background-position:right .5rem center,center right 1.5rem;background-size:16px 12px,calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.6em + 0.5rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--bs-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--bs-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{--bs-btn-padding-x: 0.5rem;--bs-btn-padding-y: 0.25rem;--bs-btn-font-family: ;--bs-btn-font-size:0.875rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.6;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 1;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg)}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #000;--bs-btn-bg: #1a85ff;--bs-btn-border-color: #1a85ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #3c97ff;--bs-btn-hover-border-color: #3191ff;--bs-btn-focus-shadow-rgb: 22, 113, 217;--bs-btn-active-color: #000;--bs-btn-active-bg: #489dff;--bs-btn-active-border-color: #3191ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #1a85ff;--bs-btn-disabled-border-color: #1a85ff}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #000;--bs-btn-bg: #689f38;--bs-btn-border-color: #689f38;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #7fad56;--bs-btn-hover-border-color: #77a94c;--bs-btn-focus-shadow-rgb: 88, 135, 48;--bs-btn-active-color: #000;--bs-btn-active-bg: #86b260;--bs-btn-active-border-color: #77a94c;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #689f38;--bs-btn-disabled-border-color: #689f38}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #00b4ff;--bs-btn-border-color: #00b4ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #26bfff;--bs-btn-hover-border-color: #1abcff;--bs-btn-focus-shadow-rgb: 0, 153, 217;--bs-btn-active-color: #000;--bs-btn-active-bg: #33c3ff;--bs-btn-active-border-color: #1abcff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #00b4ff;--bs-btn-disabled-border-color: #00b4ff}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #fdc935;--bs-btn-border-color: #fdc935;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #fdd153;--bs-btn-hover-border-color: #fdce49;--bs-btn-focus-shadow-rgb: 215, 171, 45;--bs-btn-active-color: #000;--bs-btn-active-bg: #fdd45d;--bs-btn-active-border-color: #fdce49;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #fdc935;--bs-btn-disabled-border-color: #fdc935}.btn-danger{--bs-btn-color: #000;--bs-btn-bg: #ff5267;--bs-btn-border-color: #ff5267;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ff6c7e;--bs-btn-hover-border-color: #ff6376;--bs-btn-focus-shadow-rgb: 217, 70, 88;--bs-btn-active-color: #000;--bs-btn-active-bg: #ff7585;--bs-btn-active-border-color: #ff6376;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ff5267;--bs-btn-disabled-border-color: #ff5267}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #1a85ff;--bs-btn-border-color: #1a85ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #1a85ff;--bs-btn-hover-border-color: #1a85ff;--bs-btn-focus-shadow-rgb: 26, 133, 255;--bs-btn-active-color: #000;--bs-btn-active-bg: #1a85ff;--bs-btn-active-border-color: #1a85ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #1a85ff;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #1a85ff;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #689f38;--bs-btn-border-color: #689f38;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #689f38;--bs-btn-hover-border-color: #689f38;--bs-btn-focus-shadow-rgb: 104, 159, 56;--bs-btn-active-color: #000;--bs-btn-active-bg: #689f38;--bs-btn-active-border-color: #689f38;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #689f38;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #689f38;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #00b4ff;--bs-btn-border-color: #00b4ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #00b4ff;--bs-btn-hover-border-color: #00b4ff;--bs-btn-focus-shadow-rgb: 0, 180, 255;--bs-btn-active-color: #000;--bs-btn-active-bg: #00b4ff;--bs-btn-active-border-color: #00b4ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #00b4ff;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #00b4ff;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #fdc935;--bs-btn-border-color: #fdc935;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #fdc935;--bs-btn-hover-border-color: #fdc935;--bs-btn-focus-shadow-rgb: 253, 201, 53;--bs-btn-active-color: #000;--bs-btn-active-bg: #fdc935;--bs-btn-active-border-color: #fdc935;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fdc935;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #fdc935;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #ff5267;--bs-btn-border-color: #ff5267;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ff5267;--bs-btn-hover-border-color: #ff5267;--bs-btn-focus-shadow-rgb: 255, 82, 103;--bs-btn-active-color: #000;--bs-btn-active-bg: #ff5267;--bs-btn-active-border-color: #ff5267;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff5267;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff5267;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 22, 113, 217;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.65625rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden}.collapsing.collapse-horizontal{width:0;height:auto}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:0.875rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: var(--bs-box-shadow);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #1a85ff;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 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(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.65625rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #1a85ff;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--bs-border-width)*-1)}.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:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(var(--bs-border-width)*-1)}.nav{--bs-nav-link-padding-x: 0.5rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:none;border:0}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: var(--bs-border-width);--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #1a85ff}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.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:700;color:var(--bs-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{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: 0.5rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 0.875rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25rem;--bs-navbar-toggler-padding-x: 0.75rem;--bs-navbar-toggler-font-size: 0.875rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color)}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.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(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.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]{--bs-navbar-color: rgba(255, 255, 255, 0.55);--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.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}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: transparent;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: 0;--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - 0);--bs-accordion-btn-padding-x: 0;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 0.75rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230a3566' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-accordion-body-padding-x: 0;--bs-accordion-body-padding-y: 0;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:0.875rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width)}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2376b6ff'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2376b6ff'%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{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:0.875rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #1a85ff;--bs-pagination-active-border-color: #1a85ff;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color)}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width)*-1)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.65625rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.65625rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #1a85ff;--bs-progress-bar-transition: width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg)}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #1a85ff;--bs-list-group-active-border-color: #1a85ff;display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: var(--bs-box-shadow-sm);--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0, -50px)}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.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}.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}.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}.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}.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}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.65625rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-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(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.65625rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow: var(--bs-box-shadow);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:0.875rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-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(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0}.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}.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:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")*/}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")*/}.carousel-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 rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5}.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(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin:calc(-0.5*var(--bs-offcanvas-padding-y)) calc(-0.5*var(--bs-offcanvas-padding-x)) calc(-0.5*var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#000 !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#000 !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#000 !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(72, 157, 255, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(72, 157, 255, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(134, 178, 96, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(134, 178, 96, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(51, 195, 255, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(51, 195, 255, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(253, 212, 93, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(253, 212, 93, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(255, 117, 133, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 117, 133, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{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;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-none{-o-object-fit:none !important;object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.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(--bs-box-shadow) !important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm) !important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg) !important}.shadow-none{box-shadow:none !important}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-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:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-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{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.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:3rem !important}.column-gap-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.34375rem + 1.125vw) !important}.fs-2{font-size:calc(1.3rem + 0.6vw) !important}.fs-3{font-size:calc(1.278125rem + 0.3375vw) !important}.fs-4{font-size:calc(1.25625rem + 0.075vw) !important}.fs-5{font-size:1.09375rem !important}.fs-6{font-size:0.875rem !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{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{-webkit-user-select:all !important;-moz-user-select:all !important;user-select:all !important}.user-select-auto{-webkit-user-select:auto !important;-moz-user-select:auto !important;user-select:auto !important}.user-select-none{-webkit-user-select:none !important;-moz-user-select:none !important;user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-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(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-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(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-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(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-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(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-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(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-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(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-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(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-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}@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{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-sm-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-sm-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-sm-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-sm-none{-o-object-fit:none !important;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:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.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:3rem !important}.column-gap-sm-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-sm-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-sm-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-sm-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-sm-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-sm-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-md-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-md-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-md-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-md-none{-o-object-fit:none !important;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:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.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:3rem !important}.column-gap-md-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-md-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-md-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-md-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-md-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-md-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-lg-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-lg-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-lg-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-lg-none{-o-object-fit:none !important;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:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.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:3rem !important}.column-gap-lg-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-lg-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-lg-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-lg-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-lg-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-lg-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-xl-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-xl-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-xl-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-xl-none{-o-object-fit:none !important;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:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.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:3rem !important}.column-gap-xl-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-xl-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-xl-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-xl-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-xl-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-xl-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-xxl-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-xxl-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-xxl-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-xxl-none{-o-object-fit:none !important;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:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.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:3rem !important}.column-gap-xxl-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-xxl-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-xxl-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-xxl-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-xxl-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-xxl-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}@media(min-width: 1200px){.fs-1{font-size:2.1875rem !important}.fs-2{font-size:1.75rem !important}.fs-3{font-size:1.53125rem !important}.fs-4{font-size:1.3125rem !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,[data-bs-theme=dark]{--elevation-0: 0 1px 1px 0 rgba(20, 23, 33, 0.8784313725), 0 0 1px 0 rgba(20, 23, 33, 0.8784313725);--elevation-0-inverted: 0 1px 1px 0 rgba(20, 23, 33, 0.0784313725), 0 0 1px 0 rgba(20, 23, 33, 0.3803921569);--elevation-1: 0 2px 4px -1px rgba(20, 23, 33, 0.3803921569), 0 1px 2px -1px rgba(20, 23, 33, 0.8784313725);--elevation-1-inverted: 0 2px 4px 1px rgba(20, 23, 33, 0.1215686275), 0 1px 2px 0 rgba(20, 23, 33, 0.1215686275);--elevation-2: 0 4px 8px 0 rgba(20, 23, 33, 0.3803921569), 0 2px 4px -1px rgba(20, 23, 33, 0.8784313725);--elevation-2-inverted: 0 4px 8px 0 rgba(20, 23, 33, 0.1215686275), 0 2px 4px -1px rgba(20, 23, 33, 0.0784313725);--elevation-3: 0 8px 12px 1px rgba(20, 23, 33, 0.3803921569), 0 4px 8px -1px rgba(20, 23, 33, 0.8784313725);--elevation-3-inverted: 0 8px 12px 1px rgba(20, 23, 33, 0.1215686275), 0 4px 8px -1px rgba(20, 23, 33, 0.0784313725);--elevation-4: 0 16px 32px 2px rgba(20, 23, 33, 0.3803921569), 0 8px 16px -2px rgba(20, 23, 33, 0.8784313725);--elevation-4-inverted: 0 16px 32px 2px rgba(20, 23, 33, 0.1215686275), 0 8px 16px -2px rgba(20, 23, 33, 0.0784313725);--primary-50: #373a44;--primary-50-inverted: white;--primary-100: #333640;--primary-100-inverted: #fafafb;--primary-200: #2f323c;--primary-200-inverted: #f5f6f6;--primary-300: #2b2e39;--primary-300-inverted: #f2f3f4;--primary-400: #272a35;--primary-400-inverted: #ebedee;--primary-500: #232632;--primary-500-inverted: #e6e8ea;--primary-600: #1f222e;--primary-600-inverted: #e2e4e6;--primary-700: #1b1e2a;--primary-700-inverted: #dddfe1;--primary-800: #181b26;--primary-800-inverted: #d8dadd;--primary-900: #141721;--primary-900-inverted: #d3d6d9;--text-placeholder: rgba(255, 255, 255, 0.3803921569);--text-placeholder-inverted: rgba(20, 23, 33, 0.3803921569);--text-secondary: rgba(255, 255, 255, 0.6);--text-secondary-inverted: rgba(20, 23, 33, 0.6);--text-primary: rgba(255, 255, 255, 0.8784313725);--text-primary-inverted: rgba(20, 23, 33, 0.8784313725);--text-primaryHover: white;--text-primaryHover-inverted: #141721;--text-disabled: rgba(255, 255, 255, 0.3019607843);--text-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--fill-subtle: rgba(255, 255, 255, 0.1019607843);--fill-subtle-inverted: rgba(20, 23, 33, 0.1019607843);--fill-secondary: rgba(255, 255, 255, 0.6);--fill-secondary-inverted: rgba(20, 23, 33, 0.6);--fill-primary: rgba(255, 255, 255, 0.8784313725);--fill-primary-inverted: rgba(20, 23, 33, 0.8784313725);--fill-enabled: rgba(255, 255, 255, 0.6);--fill-enabled-inverted: rgba(20, 23, 33, 0.6);--fill-active: rgba(255, 255, 255, 0.8784313725);--fill-active-inverted: rgba(20, 23, 33, 0.8784313725);--fill-hoverSelected: white;--fill-hoverSelected-inverted: #141721;--fill-disabled: rgba(255, 255, 255, 0.3019607843);--fill-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--border-subtleAlpha01: rgba(255, 255, 255, 0.1019607843);--border-subtleAlpha01-inverted: rgba(20, 23, 33, 0.1019607843);--border-subtleAlpha02: rgba(255, 255, 255, 0.1607843137);--border-subtleAlpha02-inverted: rgba(20, 23, 33, 0.1607843137);--border-subtleAlpha03: rgba(255, 255, 255, 0.2392156863);--border-subtleAlpha03-inverted: rgba(20, 23, 33, 0.2392156863);--border-enabled: rgba(255, 255, 255, 0.6);--border-enabled-inverted: rgba(20, 23, 33, 0.6);--border-hover: rgba(255, 255, 255, 0.8784313725);--border-hover-inverted: rgba(20, 23, 33, 0.8784313725);--border-disabled: rgba(255, 255, 255, 0.3019607843);--border-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--border-selected: white;--border-selected-inverted: #141721;--border-selectedInverse: #141721;--border-selectedInverse-inverted: white;--stateOverlays-enabled: rgba(255, 255, 255, 0);--stateOverlays-enabled-inverted: rgba(20, 23, 33, 0);--stateOverlays-hover: rgba(255, 255, 255, 0.0392156863);--stateOverlays-hover-inverted: rgba(20, 23, 33, 0.0588235294);--stateOverlays-active: rgba(255, 255, 255, 0.0784313725);--stateOverlays-active-inverted: rgba(20, 23, 33, 0.1215686275);--stateOverlays-disabled: rgba(4, 19, 31, 0.1607843137);--stateOverlays-disabled-inverted: rgba(20, 23, 33, 0.1607843137);--stateOverlays-selected: #2b2e39;--stateOverlays-selected-inverted: #fafafb;--stateOverlays-selectedHover: rgba(255, 255, 255, 0.1607843137);--stateOverlays-selectedHover-inverted: rgba(20, 23, 33, 0.2392156863);--stateOverlays-selectedInverse: white;--stateOverlays-selectedInverse-inverted: #141721;--stateOverlays-selectedRange: rgba(255, 255, 255, 0.1019607843);--stateOverlays-selectedRange-inverted: rgba(20, 23, 33, 0.0784313725);--field-enabled: #2b2e39;--field-enabled-inverted: #fafafb;--field-hover: #373a44;--field-hover-inverted: white;--field-disabled: #272a35;--field-disabled-inverted: #f0f1f2;--status-success: #40d86e;--status-success-inverted: #26bf56;--status-error: #f56565;--status-error-inverted: #f03b3a;--status-information: #00b4ff;--status-information-inverted: #009eff;--status-warning: #ffc107;--status-warning-inverted: #f17c02;--focus: rgba(0, 133, 255, 0.6);--focus-inverted: rgba(0, 133, 255, 0.6);--surfaces-bg01: #232632;--surfaces-bg01-inverted: white;--surfaces-bg02: #1b1e2a;--surfaces-bg02-inverted: #f5f6f6;--surfaces-bg03: #141721;--surfaces-bg03-inverted: #e6e8ea;--categorical-01Cyan: #00b4ff;--categorical-01Cyan-inverted: #00b4ff;--categorical-02Orange: #ff9222;--categorical-02Orange-inverted: #ff9222;--categorical-03Purple: #3949ab;--categorical-03Purple-inverted: #3949ab;--categorical-04Red: #ff5267;--categorical-04Red-inverted: #ff5267;--categorical-05Teal: #08bdba;--categorical-05Teal-inverted: #08bdba;--categorical-06Amber: #fdc935;--categorical-06Amber-inverted: #fdc935;--categorical-07Green: #689f38;--categorical-07Green-inverted: #689f38;--categorical-08Purple: #976fd1;--categorical-08Purple-inverted: #976fd1;--categorical-09Pink: #f781bf;--categorical-09Pink-inverted: #f781bf;--categorical-10DarkGreen: #52733e;--categorical-10DarkGreen-inverted: #52733e;--sequentialCyan-100: #afe7f9;--sequentialCyan-100-inverted: #afe7f9;--sequentialCyan-200: #8bd0f6;--sequentialCyan-200-inverted: #8bd0f6;--sequentialCyan-300: #6cbaec;--sequentialCyan-300-inverted: #6cbaec;--sequentialCyan-400: #52a3dd;--sequentialCyan-400-inverted: #52a3dd;--sequentialCyan-500: #3b8dcb;--sequentialCyan-500-inverted: #3b8dcb;--sequentialCyan-600: #2777b7;--sequentialCyan-600-inverted: #2777b7;--sequentialCyan-700: #1661a2;--sequentialCyan-700-inverted: #1661a2;--sequentialCyan-800: #074c8c;--sequentialCyan-800-inverted: #074c8c;--sequentialCyan-900: #003875;--sequentialCyan-900-inverted: #003875;--sequentialOrange-100: #f9d8ac;--sequentialOrange-100-inverted: #f9d8ac;--sequentialOrange-200: #feb85b;--sequentialOrange-200-inverted: #feb85b;--sequentialOrange-300: #f09b32;--sequentialOrange-300-inverted: #f09b32;--sequentialOrange-400: #db811e;--sequentialOrange-400-inverted: #db811e;--sequentialOrange-500: #c76809;--sequentialOrange-500-inverted: #c76809;--sequentialOrange-600: #b05000;--sequentialOrange-600-inverted: #b05000;--sequentialOrange-700: #973a00;--sequentialOrange-700-inverted: #973a00;--sequentialOrange-800: #7e2400;--sequentialOrange-800-inverted: #7e2400;--sequentialOrange-900: #640d00;--sequentialOrange-900-inverted: #640d00;--sequentialIndigo-100: #dfd8fa;--sequentialIndigo-100-inverted: #dfd8fa;--sequentialIndigo-200: #c3c1ed;--sequentialIndigo-200-inverted: #c3c1ed;--sequentialIndigo-300: #aba8e0;--sequentialIndigo-300-inverted: #aba8e0;--sequentialIndigo-400: #9390d2;--sequentialIndigo-400-inverted: #9390d2;--sequentialIndigo-500: #7a79c4;--sequentialIndigo-500-inverted: #7a79c4;--sequentialIndigo-600: #6163b5;--sequentialIndigo-600-inverted: #6163b5;--sequentialIndigo-700: #474ea6;--sequentialIndigo-700-inverted: #474ea6;--sequentialIndigo-800: #2a3994;--sequentialIndigo-800-inverted: #2a3994;--sequentialIndigo-900: #002680;--sequentialIndigo-900-inverted: #002680;--sequentialYellow-100: #fff7cd;--sequentialYellow-100-inverted: #fff7cd;--sequentialYellow-200: #ffed9b;--sequentialYellow-200-inverted: #ffed9b;--sequentialYellow-300: #ffe16a;--sequentialYellow-300-inverted: #ffe16a;--sequentialYellow-400: #ffd545;--sequentialYellow-400-inverted: #ffd545;--sequentialYellow-500: #ffc107;--sequentialYellow-500-inverted: #ffc107;--sequentialYellow-600: #dba005;--sequentialYellow-600-inverted: #dba005;--sequentialYellow-700: #b78103;--sequentialYellow-700-inverted: #b78103;--sequentialYellow-800: #936402;--sequentialYellow-800-inverted: #936402;--sequentialYellow-900: #7a4f01;--sequentialYellow-900-inverted: #7a4f01;--sequentialTeal-100: #a5eae8;--sequentialTeal-100-inverted: #a5eae8;--sequentialTeal-200: #7dd5d3;--sequentialTeal-200-inverted: #7dd5d3;--sequentialTeal-300: #5ebfbc;--sequentialTeal-300-inverted: #5ebfbc;--sequentialTeal-400: #44a8a6;--sequentialTeal-400-inverted: #44a8a6;--sequentialTeal-500: #2e9190;--sequentialTeal-500-inverted: #2e9190;--sequentialTeal-600: #1b7b7a;--sequentialTeal-600-inverted: #1b7b7a;--sequentialTeal-700: #0c6565;--sequentialTeal-700-inverted: #0c6565;--sequentialTeal-800: #025050;--sequentialTeal-800-inverted: #025050;--sequentialTeal-900: #003b3c;--sequentialTeal-900-inverted: #003b3c;--sequentialRed-100: #f8d6da;--sequentialRed-100-inverted: #f8d6da;--sequentialRed-200: #fcb6ba;--sequentialRed-200-inverted: #fcb6ba;--sequentialRed-300: #f8989b;--sequentialRed-300-inverted: #f8989b;--sequentialRed-400: #ed7b7f;--sequentialRed-400-inverted: #ed7b7f;--sequentialRed-500: #dd6065;--sequentialRed-500-inverted: #dd6065;--sequentialRed-600: #c9474c;--sequentialRed-600-inverted: #c9474c;--sequentialRed-700: #b22f36;--sequentialRed-700-inverted: #b22f36;--sequentialRed-800: #981822;--sequentialRed-800-inverted: #981822;--sequentialRed-900: #7d000f;--sequentialRed-900-inverted: #7d000f;--surfaces-bg-card: #232632;--surfaces-bg-card-inverted: #F5F6F6;--bs-primary-rgb: #ffffffe0;--bs-secondary-color: #ffffff99;--bs-nav-link-color: #ffffff99;--bs-form-valid-color: #40d86eff;--bs-form-invalid-color: #f56565ff;--bs-body-bg: #141721}[data-bs-theme=light]{--elevation-0: 0 1px 1px 0 rgba(20, 23, 33, 0.0784313725), 0 0 1px 0 rgba(20, 23, 33, 0.3803921569);--elevation-0-inverted: 0 1px 1px 0 rgba(20, 23, 33, 0.8784313725), 0 0 1px 0 rgba(20, 23, 33, 0.8784313725);--elevation-1: 0 2px 4px 1px rgba(20, 23, 33, 0.1215686275), 0 1px 2px 0 rgba(20, 23, 33, 0.1215686275);--elevation-1-inverted: 0 2px 4px -1px rgba(20, 23, 33, 0.3803921569), 0 1px 2px -1px rgba(20, 23, 33, 0.8784313725);--elevation-2: 0 4px 8px 0 rgba(20, 23, 33, 0.1215686275), 0 2px 4px -1px rgba(20, 23, 33, 0.0784313725);--elevation-2-inverted: 0 4px 8px 0 rgba(20, 23, 33, 0.3803921569), 0 2px 4px -1px rgba(20, 23, 33, 0.8784313725);--elevation-3: 0 8px 12px 1px rgba(20, 23, 33, 0.1215686275), 0 4px 8px -1px rgba(20, 23, 33, 0.0784313725);--elevation-3-inverted: 0 8px 12px 1px rgba(20, 23, 33, 0.3803921569), 0 4px 8px -1px rgba(20, 23, 33, 0.8784313725);--elevation-4: 0 16px 32px 2px rgba(20, 23, 33, 0.1215686275), 0 8px 16px -2px rgba(20, 23, 33, 0.0784313725);--elevation-4-inverted: 0 16px 32px 2px rgba(20, 23, 33, 0.3803921569), 0 8px 16px -2px rgba(20, 23, 33, 0.8784313725);--primary-50: white;--primary-50-inverted: #373a44;--primary-100: #fafafb;--primary-100-inverted: #333640;--primary-200: #f5f6f6;--primary-200-inverted: #2f323c;--primary-300: #f2f3f4;--primary-300-inverted: #2b2e39;--primary-400: #ebedee;--primary-400-inverted: #272a35;--primary-500: #e6e8ea;--primary-500-inverted: #232632;--primary-600: #e2e4e6;--primary-600-inverted: #1f222e;--primary-700: #dddfe1;--primary-700-inverted: #1b1e2a;--primary-800: #d8dadd;--primary-800-inverted: #181b26;--primary-900: #d3d6d9;--primary-900-inverted: #141721;--text-placeholder: rgba(20, 23, 33, 0.3803921569);--text-placeholder-inverted: rgba(255, 255, 255, 0.3803921569);--text-secondary: rgba(20, 23, 33, 0.6);--text-secondary-inverted: rgba(255, 255, 255, 0.6);--text-primary: rgba(20, 23, 33, 0.8784313725);--text-primary-inverted: rgba(255, 255, 255, 0.8784313725);--text-primaryHover: #141721;--text-primaryHover-inverted: white;--text-disabled: rgba(20, 23, 33, 0.3019607843);--text-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--fill-subtle: rgba(20, 23, 33, 0.1019607843);--fill-subtle-inverted: rgba(255, 255, 255, 0.1019607843);--fill-secondary: rgba(20, 23, 33, 0.6);--fill-secondary-inverted: rgba(255, 255, 255, 0.6);--fill-primary: rgba(20, 23, 33, 0.8784313725);--fill-primary-inverted: rgba(255, 255, 255, 0.8784313725);--fill-enabled: rgba(20, 23, 33, 0.6);--fill-enabled-inverted: rgba(255, 255, 255, 0.6);--fill-active: rgba(20, 23, 33, 0.8784313725);--fill-active-inverted: rgba(255, 255, 255, 0.8784313725);--fill-hoverSelected: #141721;--fill-hoverSelected-inverted: white;--fill-disabled: rgba(20, 23, 33, 0.3019607843);--fill-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--border-subtleAlpha01: rgba(20, 23, 33, 0.1019607843);--border-subtleAlpha01-inverted: rgba(255, 255, 255, 0.1019607843);--border-subtleAlpha02: rgba(20, 23, 33, 0.1607843137);--border-subtleAlpha02-inverted: rgba(255, 255, 255, 0.1607843137);--border-subtleAlpha03: rgba(20, 23, 33, 0.2392156863);--border-subtleAlpha03-inverted: rgba(255, 255, 255, 0.2392156863);--border-enabled: rgba(20, 23, 33, 0.6);--border-enabled-inverted: rgba(255, 255, 255, 0.6);--border-hover: rgba(20, 23, 33, 0.8784313725);--border-hover-inverted: rgba(255, 255, 255, 0.8784313725);--border-disabled: rgba(20, 23, 33, 0.3019607843);--border-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--border-selected: #141721;--border-selected-inverted: white;--border-selectedInverse: white;--border-selectedInverse-inverted: #141721;--stateOverlays-enabled: rgba(20, 23, 33, 0);--stateOverlays-enabled-inverted: rgba(255, 255, 255, 0);--stateOverlays-hover: rgba(20, 23, 33, 0.0588235294);--stateOverlays-hover-inverted: rgba(255, 255, 255, 0.0392156863);--stateOverlays-active: rgba(20, 23, 33, 0.1215686275);--stateOverlays-active-inverted: rgba(255, 255, 255, 0.0784313725);--stateOverlays-disabled: rgba(20, 23, 33, 0.1607843137);--stateOverlays-disabled-inverted: rgba(4, 19, 31, 0.1607843137);--stateOverlays-selected: #fafafb;--stateOverlays-selected-inverted: #2b2e39;--stateOverlays-selectedHover: rgba(20, 23, 33, 0.2392156863);--stateOverlays-selectedHover-inverted: rgba(255, 255, 255, 0.1607843137);--stateOverlays-selectedInverse: #141721;--stateOverlays-selectedInverse-inverted: white;--stateOverlays-selectedRange: rgba(20, 23, 33, 0.0784313725);--stateOverlays-selectedRange-inverted: rgba(255, 255, 255, 0.1019607843);--field-enabled: #fafafb;--field-enabled-inverted: #2b2e39;--field-hover: white;--field-hover-inverted: #373a44;--field-disabled: #f0f1f2;--field-disabled-inverted: #272a35;--status-success: #26bf56;--status-success-inverted: #40d86e;--status-error: #f03b3a;--status-error-inverted: #f56565;--status-information: #009eff;--status-information-inverted: #00b4ff;--status-warning: #f17c02;--status-warning-inverted: #ffc107;--focus: rgba(0, 133, 255, 0.6);--focus-inverted: rgba(0, 133, 255, 0.6);--surfaces-bg01: white;--surfaces-bg01-inverted: #232632;--surfaces-bg02: #f5f6f6;--surfaces-bg02-inverted: #1b1e2a;--surfaces-bg03: #e6e8ea;--surfaces-bg03-inverted: #141721;--categorical-01Cyan: #00b4ff;--categorical-01Cyan-inverted: #00b4ff;--categorical-02Orange: #ff9222;--categorical-02Orange-inverted: #ff9222;--categorical-03Purple: #3949ab;--categorical-03Purple-inverted: #3949ab;--categorical-04Red: #ff5267;--categorical-04Red-inverted: #ff5267;--categorical-05Teal: #08bdba;--categorical-05Teal-inverted: #08bdba;--categorical-06Amber: #fdc935;--categorical-06Amber-inverted: #fdc935;--categorical-07Green: #689f38;--categorical-07Green-inverted: #689f38;--categorical-08Purple: #976fd1;--categorical-08Purple-inverted: #976fd1;--categorical-09Pink: #f781bf;--categorical-09Pink-inverted: #f781bf;--categorical-10DarkGreen: #52733e;--categorical-10DarkGreen-inverted: #52733e;--sequentialCyan-100: #afe7f9;--sequentialCyan-100-inverted: #afe7f9;--sequentialCyan-200: #8bd0f6;--sequentialCyan-200-inverted: #8bd0f6;--sequentialCyan-300: #6cbaec;--sequentialCyan-300-inverted: #6cbaec;--sequentialCyan-400: #52a3dd;--sequentialCyan-400-inverted: #52a3dd;--sequentialCyan-500: #3b8dcb;--sequentialCyan-500-inverted: #3b8dcb;--sequentialCyan-600: #2777b7;--sequentialCyan-600-inverted: #2777b7;--sequentialCyan-700: #1661a2;--sequentialCyan-700-inverted: #1661a2;--sequentialCyan-800: #074c8c;--sequentialCyan-800-inverted: #074c8c;--sequentialCyan-900: #003875;--sequentialCyan-900-inverted: #003875;--sequentialOrange-100: #f9d8ac;--sequentialOrange-100-inverted: #f9d8ac;--sequentialOrange-200: #feb85b;--sequentialOrange-200-inverted: #feb85b;--sequentialOrange-300: #f09b32;--sequentialOrange-300-inverted: #f09b32;--sequentialOrange-400: #db811e;--sequentialOrange-400-inverted: #db811e;--sequentialOrange-500: #c76809;--sequentialOrange-500-inverted: #c76809;--sequentialOrange-600: #b05000;--sequentialOrange-600-inverted: #b05000;--sequentialOrange-700: #973a00;--sequentialOrange-700-inverted: #973a00;--sequentialOrange-800: #7e2400;--sequentialOrange-800-inverted: #7e2400;--sequentialOrange-900: #640d00;--sequentialOrange-900-inverted: #640d00;--sequentialIndigo-100: #dfd8fa;--sequentialIndigo-100-inverted: #dfd8fa;--sequentialIndigo-200: #c3c1ed;--sequentialIndigo-200-inverted: #c3c1ed;--sequentialIndigo-300: #aba8e0;--sequentialIndigo-300-inverted: #aba8e0;--sequentialIndigo-400: #9390d2;--sequentialIndigo-400-inverted: #9390d2;--sequentialIndigo-500: #7a79c4;--sequentialIndigo-500-inverted: #7a79c4;--sequentialIndigo-600: #6163b5;--sequentialIndigo-600-inverted: #6163b5;--sequentialIndigo-700: #474ea6;--sequentialIndigo-700-inverted: #474ea6;--sequentialIndigo-800: #2a3994;--sequentialIndigo-800-inverted: #2a3994;--sequentialIndigo-900: #002680;--sequentialIndigo-900-inverted: #002680;--sequentialYellow-100: #fff7cd;--sequentialYellow-100-inverted: #fff7cd;--sequentialYellow-200: #ffed9b;--sequentialYellow-200-inverted: #ffed9b;--sequentialYellow-300: #ffe16a;--sequentialYellow-300-inverted: #ffe16a;--sequentialYellow-400: #ffd545;--sequentialYellow-400-inverted: #ffd545;--sequentialYellow-500: #ffc107;--sequentialYellow-500-inverted: #ffc107;--sequentialYellow-600: #dba005;--sequentialYellow-600-inverted: #dba005;--sequentialYellow-700: #b78103;--sequentialYellow-700-inverted: #b78103;--sequentialYellow-800: #936402;--sequentialYellow-800-inverted: #936402;--sequentialYellow-900: #7a4f01;--sequentialYellow-900-inverted: #7a4f01;--sequentialTeal-100: #a5eae8;--sequentialTeal-100-inverted: #a5eae8;--sequentialTeal-200: #7dd5d3;--sequentialTeal-200-inverted: #7dd5d3;--sequentialTeal-300: #5ebfbc;--sequentialTeal-300-inverted: #5ebfbc;--sequentialTeal-400: #44a8a6;--sequentialTeal-400-inverted: #44a8a6;--sequentialTeal-500: #2e9190;--sequentialTeal-500-inverted: #2e9190;--sequentialTeal-600: #1b7b7a;--sequentialTeal-600-inverted: #1b7b7a;--sequentialTeal-700: #0c6565;--sequentialTeal-700-inverted: #0c6565;--sequentialTeal-800: #025050;--sequentialTeal-800-inverted: #025050;--sequentialTeal-900: #003b3c;--sequentialTeal-900-inverted: #003b3c;--sequentialRed-100: #f8d6da;--sequentialRed-100-inverted: #f8d6da;--sequentialRed-200: #fcb6ba;--sequentialRed-200-inverted: #fcb6ba;--sequentialRed-300: #f8989b;--sequentialRed-300-inverted: #f8989b;--sequentialRed-400: #ed7b7f;--sequentialRed-400-inverted: #ed7b7f;--sequentialRed-500: #dd6065;--sequentialRed-500-inverted: #dd6065;--sequentialRed-600: #c9474c;--sequentialRed-600-inverted: #c9474c;--sequentialRed-700: #b22f36;--sequentialRed-700-inverted: #b22f36;--sequentialRed-800: #981822;--sequentialRed-800-inverted: #981822;--sequentialRed-900: #7d000f;--sequentialRed-900-inverted: #7d000f;--surfaces-bg-card: #F5F6F6;--surfaces-bg-card-inverted: #232632;--bs-primary-rgb: #141721e0;--bs-secondary-color: #14172199;--bs-nav-link-color: #14172199;--bs-form-valid-color: #26bf56ff;--bs-form-invalid-color: #f03b3aff;--bs-body-bg: white}[data-bs-theme=dark]{--bs-primary: #1b0734;--bs-secondary: #808080;--bs-success: #222222;--bs-danger: #be3636;--bs-info: #163960;--bs-dark: #2a2a2a;--bs-light: #333333;--bs-primary-rgb: 27, 7, 52;--bs-secondary-rgb: 128, 128, 128;--bs-success-rgb: 34, 34, 34;--bs-danger-rgb: 190, 54, 54;--bs-info-rgb: 22, 57, 96;--bs-dark-rgb: 42, 42, 42;--bs-light-rgb: 51, 51, 51}[data-bs-theme=light]{--bs-primary: #1b0734;--bs-secondary: #808080;--bs-success: #222222;--bs-danger: #be3636;--bs-info: #163960;--bs-dark: #2a2a2a;--bs-light: #333333;--bs-primary-rgb: 27, 7, 52;--bs-secondary-rgb: 128, 128, 128;--bs-success-rgb: 34, 34, 34;--bs-danger-rgb: 190, 54, 54;--bs-info-rgb: 22, 57, 96;--bs-dark-rgb: 42, 42, 42;--bs-light-rgb: 51, 51, 51}h1,.h1{font-size:32px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.128px;line-height:40px;color:var(--text-primary)}h2,.h2{font-size:24px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.096px;line-height:32px;color:var(--text-primary)}h3,.h3,legend{font-size:20px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:0px;line-height:28px;color:var(--text-primary)}h4,.h4{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;color:var(--text-primary)}h5,.h5{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;font-size:14px;color:var(--text-primary)}h6,.h6{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;font-size:12px;color:var(--text-primary)}p,label,ul,li,blockquote{color:var(--text-secondary)}.text-muted{color:var(--text-subtle)}.text-primary{color:var(--text-primary) !important}.text-secondary{color:var(--text-secondary) !important}blockquote{border-left:.25rem var(--text-secondary) solid;margin-bottom:.5rem;padding-left:.25rem}hr{border-bottom:1px solid var(--border-subtleAlpha01);width:100%}li{margin-bottom:.25rem}.btn{width:-moz-fit-content;width:fit-content;height:32px}.btn-large{height:40px}.btn-primary{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0);transition:box-shadow .2s}.btn-primary:enabled,.btn-primary.enabled{border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:active,.btn-primary.active{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-active-inverted), var(--stateOverlays-active-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:hover,.btn-primary.hover{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-hover-inverted), var(--stateOverlays-hover-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-1)}.btn-primary:focus,.btn-primary.focus{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:1px solid rgba(0,0,0,0);box-shadow:var(--elevation-0);outline:2px solid var(--focus-color)}.btn-primary:disabled,.btn-primary.disabled{color:var(--text-disabled-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-disabled-inverted), var(--stateOverlays-disabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-secondary{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-enabled);box-shadow:var(--elevation-0);transition:box-shadow .2s}.btn-secondary:enabled,.btn-secondary.enabled{border:1px solid var(--border-enabled);box-shadow:var(--elevation-0)}.btn-secondary:active,.btn-secondary.active{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-active);border:1px solid var(--border-selected);box-shadow:var(--elevation-0)}.btn-secondary:hover,.btn-secondary.hover{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-hover);border:1px solid var(--border-hover);box-shadow:var(--elevation-1)}.btn-secondary:focus,.btn-secondary.focus{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-hover);box-shadow:var(--elevation-0);outline:2px solid var(--focus-color)}.btn-secondary:disabled,.btn-secondary.disabled{color:var(--text-disabled);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-disabled);box-shadow:var(--elevation-0)}.btn-secondary:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-enabled);box-shadow:var(--elevation-0)}.btn-tertiary,.btn-link{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None;transition:box-shadow .2s}.btn-tertiary:enabled,.btn-tertiary.enabled,.btn-link:enabled,.btn-link.enabled{border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:active,.btn-tertiary.active,.btn-link:active,.btn-link.active{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-active);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:hover,.btn-tertiary.hover,.btn-link:hover,.btn-link.hover{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-hover);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-1)}.btn-tertiary:focus,.btn-tertiary.focus,.btn-link:focus,.btn-link.focus{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid rgba(0,0,0,0);box-shadow:None;outline:2px solid var(--focus-color)}.btn-tertiary:disabled,.btn-tertiary.disabled,.btn-link:disabled,.btn-link.disabled{color:var(--text-disabled);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:focus:not(:focus-visible,:disabled,.disabled),.btn-link:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary,.btn-tertiary:disabled,.btn-tertiary.disabled,.btn-link,.btn-link:disabled,.btn-link.disabled{text-decoration:underline}.accordion{width:100%}.accordion-body{display:flex;flex-direction:column;gap:.5rem}.accordion-item{color:var(--text-primary);border-bottom:1px solid var(--border-subtleAlpha01)}.accordion-item .nav-link{padding:.5rem;color:var(--text-secondary)}.accordion-item .nav-link:last-child{margin-bottom:.75rem}.accordion-item .nav-link:active,.accordion-item .nav-link.active{background:var(--stateOverlays-active);color:var(--text-primary)}.accordion-item .nav-link:hover,.accordion-item .nav-link.hover{background:var(--stateOverlays-selectedHover);color:var(--text-primary)}.accordion-item .nav-link:disabled,.accordion-item .nav-link.disabled{color:var(--text-disabled)}.accordion-item .nav-link:focus:not(:focus-visible,:disabled,.disabled){background:var(--stateOverlays-active);color:var(--text-primary)}.accordion-button{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary);text-transform:uppercase;border:none;box-shadow:none}.accordion-button::after{filter:contrast(0);opacity:.4}.accordion-button:not(.collapsed){color:var(--text-primary);background-color:rgba(0,0,0,0);box-shadow:none}.accordion-button:not(.collapsed)::after{filter:contrast(0);opacity:1}.accordion-button:hover,.accordion-button.hover{color:var(--text-primary)}.accordion-button:hover::after,.accordion-button.hover::after{opacity:1}.accordion-button:focus,.accordion-button.focus{border:none;box-shadow:none}.card{background:var(--surfaces-bg-card);border:none;box-shadow:var(--elevation-1);width:100%;height:100%;overflow:auto;padding:1rem}.card-nav:hover,.card-nav.hover{background:var(--field-enabled);box-shadow:var(--elevation-2);transform:translate3d(0, -0.5rem, 0);will-change:transform}.card-title,.card-header{color:var(--text-primary)}.card-subtitle{color:var(--text-secondary)}.card-text{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary)}.card-text:last-child{margin-bottom:.5rem}.navbar{background:var(--surfaces-bg02) !important}.navbar .nav-link{padding:0;align-items:center;display:flex;height:4rem;justify-content:center;color:var(--text-secondary)}.navbar .nav-link:active,.navbar .nav-link.active{color:var(--text-primary)}.form-check{transition:all 150ms ease 0s;margin-bottom:12px;line-height:16px;min-height:auto;padding-left:28px}.form-check-inline{margin-right:12px}.form-check-input{margin:0;position:relative;border-color:var(--border-enabled);border-radius:0;color:var(--fill-active);width:16px;height:16px;outline:none;background-color:rgba(0,0,0,0);background-size:auto}.form-check-input:checked{background-color:rgba(0,0,0,0);border-color:var(--border-enabled);color:var(--fill-active)}.form-check-input[type=radio]{background-image:none}.form-check-input[type=radio]:checked::after{position:absolute;content:"";background-color:var(--fill-active);border-radius:50%;width:8px;height:8px;top:50%;left:50%;transform:translate(-50%, -50%)}.form-check-input:hover,.form-check-input.hover{border-color:var(--border-hover)}.form-check-input:active,.form-check-input.active{border-color:var(--border-selected)}.form-check-input:disabled,.form-check-input.disabled{border-color:var(--border-disabled)}.form-check-input:focus,.form-check-input.focus{border-color:var(--border-selected);box-shadow:none}.form-check-input:hover{border-color:var(--border-hover)}.form-check .form-check-input{margin-left:-24px}.form-check-label{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary)}.form-check-lg{line-height:20px;min-height:auto;padding-left:32px}.form-check-lg .form-check-input{width:20px;height:20px;border-width:2px;margin-left:-28px}.form-check-lg .form-check-label{line-height:20px}.form-check.disabled .form-check-label{color:var(--text-disabled)}[data-bs-theme=light] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=light] .form-check-lg .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='9' viewBox='0 0 11 9' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.5 1.25L9.25 0L3.5 5.75L1.25 3.5L0 4.75L3.5 8.25L10.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)' fill-opacity='0.88'/%3E%3C/svg%3E")}[data-bs-theme=dark] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=dark] .form-check-lg .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='9' viewBox='0 0 11 9' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.5 1.25L9.25 0L3.5 5.75L1.25 3.5L0 4.75L3.5 8.25L10.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)' fill-opacity='0.88'/%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-check-lg .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='9' viewBox='0 0 11 9' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.5 1.25L9.25 0L3.5 5.75L1.25 3.5L0 4.75L3.5 8.25L10.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)' fill-opacity='0.88'/%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-check-lg .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='9' viewBox='0 0 11 9' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.5 1.25L9.25 0L3.5 5.75L1.25 3.5L0 4.75L3.5 8.25L10.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)' fill-opacity='0.88'/%3E%3C/svg%3E")}.form-control,.input-group-text{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;background-color:var(--field-enabled);color:var(--text-primary);padding:.5rem;box-shadow:var(--elevation-0);border:none}.form-control::-moz-placeholder, .input-group-text::-moz-placeholder{color:var(--text-placeholder)}.form-control::placeholder,.input-group-text::placeholder{color:var(--text-placeholder)}.form-control:focus,.form-control.focus,.input-group-text:focus,.input-group-text.focus{background-color:var(--field-hover);color:var(--text-primary);box-shadow:0 0 0 2px var(--focus) inset}.form-control:hover,.form-control.hover,.input-group-text:hover,.input-group-text.hover{background-color:var(--field-hover)}.form-control:disabled,.form-control.disabled,.input-group-text:disabled,.input-group-text.disabled{background-color:var(--field-disabled);color:var(--text-disabled)}.form-control:focus-visible,.form-control.focus-visible,.input-group-text:focus-visible,.input-group-text.focus-visible{outline:none}.form-control.is-invalid{box-shadow:0 0 0 2px var(--status-error) inset;border:none}.form-control.is-invalid:focus,.form-control.is-invalid.focus{box-shadow:0 0 0 2px var(--status-error) inset}.form-control.is-valid{box-shadow:0 0 0 2px var(--status-success) inset}.form-control.is-valid:focus,.form-control.is-valid.focus{box-shadow:0 0 0 2px var(--status-success) inset}[data-bs-theme=light] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}.form-label{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary);margin-bottom:12px;width:100%}.qb-container-bg-01{background-color:var(--surfaces-bg01);padding:40px;width:100%}.qb-container-bg-02{background-color:var(--surfaces-bg02);padding:40px;width:100%}.qb-container-bg-03{background-color:var(--surfaces-bg03);padding:40px;width:100%}
+ */:root,[data-bs-theme=light]{--bs-blue: #1a85ff;--bs-indigo: #6610f2;--bs-purple: #976fd1;--bs-pink: #d41159;--bs-red: #ff5267;--bs-orange: #ff9222;--bs-yellow: #fdc935;--bs-green: #689f38;--bs-teal: #08bdba;--bs-cyan: #00b4ff;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-primary: #1a85ff;--bs-secondary: #6c757d;--bs-success: #689f38;--bs-info: #00b4ff;--bs-warning: #fdc935;--bs-danger: #ff5267;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-primary-rgb: 26, 133, 255;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 104, 159, 56;--bs-info-rgb: 0, 180, 255;--bs-warning-rgb: 253, 201, 53;--bs-danger-rgb: 255, 82, 103;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #0a3566;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #2a4016;--bs-info-text-emphasis: #004866;--bs-warning-text-emphasis: #655015;--bs-danger-text-emphasis: #662129;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #d1e7ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #e1ecd7;--bs-info-bg-subtle: #ccf0ff;--bs-warning-bg-subtle: #fff4d7;--bs-danger-bg-subtle: #ffdce1;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #a3ceff;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #c3d9af;--bs-info-border-subtle: #99e1ff;--bs-warning-border-subtle: #fee9ae;--bs-danger-border-subtle: #ffbac2;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: inter, sans-serif, arial, serif, "Segoe UI", roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size:0.875rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #1a85ff;--bs-link-color-rgb: 26, 133, 255;--bs-link-decoration: underline;--bs-link-hover-color: #156acc;--bs-link-hover-color-rgb: 21, 106, 204;--bs-code-color: #d41159;--bs-highlight-color: #212529;--bs-highlight-bg: #fff4d7;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0;--bs-border-radius-sm: 0;--bs-border-radius-lg: 0;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(26, 133, 255, 0.25);--bs-form-valid-color: #689f38;--bs-form-valid-border-color: #689f38;--bs-form-invalid-color: #ff5267;--bs-form-invalid-border-color: #ff5267}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #76b6ff;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #a4c588;--bs-info-text-emphasis: #66d2ff;--bs-warning-text-emphasis: #fedf86;--bs-danger-text-emphasis: #ff97a4;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #051b33;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #15200b;--bs-info-bg-subtle: #002433;--bs-warning-bg-subtle: #33280b;--bs-danger-bg-subtle: #331015;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #105099;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #3e5f22;--bs-info-border-subtle: #006c99;--bs-warning-border-subtle: #987920;--bs-danger-border-subtle: #99313e;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #76b6ff;--bs-link-hover-color: #91c5ff;--bs-link-color-rgb: 118, 182, 255;--bs-link-hover-color-rgb: 145, 197, 255;--bs-code-color: #e5709b;--bs-highlight-color: #dee2e6;--bs-highlight-bg: #655015;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #a4c588;--bs-form-valid-border-color: #a4c588;--bs-form-invalid-color: #ff97a4;--bs-form-invalid-border-color: #ff97a4}*,*::before,*::after{box-sizing:border-box}@media(prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.34375rem + 1.125vw)}@media(min-width: 1200px){h1,.h1{font-size:2.1875rem}}h2,.h2{font-size:calc(1.3rem + 0.6vw)}@media(min-width: 1200px){h2,.h2{font-size:1.75rem}}h3,.h3{font-size:calc(1.278125rem + 0.3375vw)}@media(min-width: 1200px){h3,.h3{font-size:1.53125rem}}h4,.h4{font-size:calc(1.25625rem + 0.075vw)}@media(min-width: 1200px){h4,.h4{font-size:1.3125rem}}h5,.h5{font-size:1.09375rem}h6,.h6{font-size:0.875rem}p{margin-top:0;margin-bottom:.5rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:0.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color)}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(--bs-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:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-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:1.09375rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.09375rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-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{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1*var(--bs-gutter-y));margin-right:calc(-0.5*var(--bs-gutter-x));margin-left:calc(-0.5*var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-0,.gy-0{--bs-gutter-y: 0}.g-1,.gx-1{--bs-gutter-x: 0.25rem}.g-1,.gy-1{--bs-gutter-y: 0.25rem}.g-2,.gx-2{--bs-gutter-x: 0.5rem}.g-2,.gy-2{--bs-gutter-y: 0.5rem}.g-3,.gx-3{--bs-gutter-x: 1rem}.g-3,.gy-3{--bs-gutter-y: 1rem}.g-4,.gx-4{--bs-gutter-x: 1.5rem}.g-4,.gy-4{--bs-gutter-y: 1.5rem}.g-5,.gx-5{--bs-gutter-x: 3rem}.g-5,.gy-5{--bs-gutter-y: 3rem}@media(min-width: 576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-sm-0,.gy-sm-0{--bs-gutter-y: 0}.g-sm-1,.gx-sm-1{--bs-gutter-x: 0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: 0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: 0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: 0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x: 3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y: 3rem}}@media(min-width: 768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-md-0,.gy-md-0{--bs-gutter-y: 0}.g-md-1,.gx-md-1{--bs-gutter-x: 0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y: 0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x: 0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y: 0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x: 1rem}.g-md-3,.gy-md-3{--bs-gutter-y: 1rem}.g-md-4,.gx-md-4{--bs-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x: 3rem}.g-md-5,.gy-md-5{--bs-gutter-y: 3rem}}@media(min-width: 992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-lg-0,.gy-lg-0{--bs-gutter-y: 0}.g-lg-1,.gx-lg-1{--bs-gutter-x: 0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: 0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: 0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: 0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x: 3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y: 3rem}}@media(min-width: 1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-xl-0,.gy-xl-0{--bs-gutter-y: 0}.g-xl-1,.gx-xl-1{--bs-gutter-x: 0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: 0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: 0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: 0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x: 3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y: 3rem}}@media(min-width: 1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.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{--bs-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x: 0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: 0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: 0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: 0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x: 3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y: 3rem}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-emphasis-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-emphasis-color);--bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color: var(--bs-emphasis-color);--bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color: var(--bs-emphasis-color);--bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width)*2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-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(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #d1e7ff;--bs-table-border-color: #a7b9cc;--bs-table-striped-bg: #c7dbf2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0e6;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #b5b6b7;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #e1ecd7;--bs-table-border-color: #b4bdac;--bs-table-striped-bg: #d6e0cc;--bs-table-striped-color: #000;--bs-table-active-bg: #cbd4c2;--bs-table-active-color: #000;--bs-table-hover-bg: #d0dac7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #ccf0ff;--bs-table-border-color: #a3c0cc;--bs-table-striped-bg: #c2e4f2;--bs-table-striped-color: #000;--bs-table-active-bg: #b8d8e6;--bs-table-active-color: #000;--bs-table-hover-bg: #bddeec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff4d7;--bs-table-border-color: #ccc3ac;--bs-table-striped-bg: #f2e8cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dcc2;--bs-table-active-color: #000;--bs-table-hover-bg: #ece2c7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #ffdce1;--bs-table-border-color: #ccb0b4;--bs-table-striped-bg: #f2d1d6;--bs-table-striped-color: #000;--bs-table-active-bg: #e6c6cb;--bs-table-active-color: #000;--bs-table-hover-bg: #ecccd0;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #c6c7c8;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: #4d5154;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #fff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #fff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-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}.col-form-label{padding-top:calc(0.25rem + var(--bs-border-width));padding-bottom:calc(0.25rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.6}.col-form-label-lg{padding-top:calc(0.5rem + var(--bs-border-width));padding-bottom:calc(0.5rem + var(--bs-border-width));font-size:0.875rem}.col-form-label-sm{padding-top:calc(0.25rem + var(--bs-border-width));padding-bottom:calc(0.25rem + var(--bs-border-width));font-size:0.65625rem}.form-text{margin-top:.25rem;font-size:0.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:0}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.6em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.25rem 0;margin-bottom:0;line-height:1.6;color:var(--bs-body-color);background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:var(--bs-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.6em + 0.5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:0.65625rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:0.875rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2));padding:.25rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important}.form-control-color::-webkit-color-swatch{border:0 !important}.form-control-color.form-control-sm{height:calc(1.6em + 0.5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.6em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-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='%23343a40' 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:.25rem 1.5rem .25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .5rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:0}.form-select:focus{border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.5rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.65625rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:0.875rem}[data-bs-theme=dark] .form-select{--bs-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='%23dee2e6' 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.3125rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#8dc2ff;outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.form-check-input:checked{background-color:#1a85ff;border-color:#1a85ff}.form-check-input:checked[type=checkbox]{--bs-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='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#1a85ff;border-color:#1a85ff;--bs-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='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-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%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:0}.form-switch .form-check-input:focus{--bs-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='%238dc2ff'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-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='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:1}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,133,255,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,133,255,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;-webkit-appearance:none;appearance:none;background-color:#1a85ff;border:0}.form-range::-webkit-slider-thumb:active{background-color:#badaff}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#1a85ff;border:0}.form-range::-moz-range-thumb:active{background-color:#badaff}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-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(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .5rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid rgba(0,0,0,0);transform-origin:0 0}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .5rem}.form-floating>.form-control::-moz-placeholder, .form-floating>.form-control-plaintext::-moz-placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:not(:-moz-placeholder-shown), .form-floating>.form-control-plaintext:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.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:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem .25rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg)}.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 .25rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:var(--bs-secondary-bg)}.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:.25rem .5rem;font-size:0.875rem;font-weight:400;line-height:1.6;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:0.875rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.65625rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:2rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width)*-1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.65625rem;color:#fff;background-color:var(--bs-success)}.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(--bs-form-valid-border-color);padding-right:calc(1.6em + 0.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23689f38' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.4em + 0.125rem) center;background-size:calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.6em + 0.5rem);background-position:top calc(0.4em + 0.125rem) right calc(0.4em + 0.125rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--bs-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"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23689f38' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:2.75rem;background-position:right .5rem center,center right 1.5rem;background-size:16px 12px,calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.6em + 0.5rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--bs-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--bs-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:0.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.65625rem;color:#fff;background-color:var(--bs-danger)}.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(--bs-form-invalid-border-color);padding-right:calc(1.6em + 0.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff5267'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff5267' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.4em + 0.125rem) center;background-size:calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.6em + 0.5rem);background-position:top calc(0.4em + 0.125rem) right calc(0.4em + 0.125rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--bs-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"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff5267'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff5267' stroke='none'/%3e%3c/svg%3e");padding-right:2.75rem;background-position:right .5rem center,center right 1.5rem;background-size:16px 12px,calc(0.8em + 0.25rem) calc(0.8em + 0.25rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.6em + 0.5rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--bs-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--bs-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{--bs-btn-padding-x: 0.5rem;--bs-btn-padding-y: 0.25rem;--bs-btn-font-family: ;--bs-btn-font-size:0.875rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.6;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 1;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg)}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #000;--bs-btn-bg: #1a85ff;--bs-btn-border-color: #1a85ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #3c97ff;--bs-btn-hover-border-color: #3191ff;--bs-btn-focus-shadow-rgb: 22, 113, 217;--bs-btn-active-color: #000;--bs-btn-active-bg: #489dff;--bs-btn-active-border-color: #3191ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #1a85ff;--bs-btn-disabled-border-color: #1a85ff}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #000;--bs-btn-bg: #689f38;--bs-btn-border-color: #689f38;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #7fad56;--bs-btn-hover-border-color: #77a94c;--bs-btn-focus-shadow-rgb: 88, 135, 48;--bs-btn-active-color: #000;--bs-btn-active-bg: #86b260;--bs-btn-active-border-color: #77a94c;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #689f38;--bs-btn-disabled-border-color: #689f38}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #00b4ff;--bs-btn-border-color: #00b4ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #26bfff;--bs-btn-hover-border-color: #1abcff;--bs-btn-focus-shadow-rgb: 0, 153, 217;--bs-btn-active-color: #000;--bs-btn-active-bg: #33c3ff;--bs-btn-active-border-color: #1abcff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #00b4ff;--bs-btn-disabled-border-color: #00b4ff}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #fdc935;--bs-btn-border-color: #fdc935;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #fdd153;--bs-btn-hover-border-color: #fdce49;--bs-btn-focus-shadow-rgb: 215, 171, 45;--bs-btn-active-color: #000;--bs-btn-active-bg: #fdd45d;--bs-btn-active-border-color: #fdce49;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #fdc935;--bs-btn-disabled-border-color: #fdc935}.btn-danger{--bs-btn-color: #000;--bs-btn-bg: #ff5267;--bs-btn-border-color: #ff5267;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ff6c7e;--bs-btn-hover-border-color: #ff6376;--bs-btn-focus-shadow-rgb: 217, 70, 88;--bs-btn-active-color: #000;--bs-btn-active-bg: #ff7585;--bs-btn-active-border-color: #ff6376;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ff5267;--bs-btn-disabled-border-color: #ff5267}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #1a85ff;--bs-btn-border-color: #1a85ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #1a85ff;--bs-btn-hover-border-color: #1a85ff;--bs-btn-focus-shadow-rgb: 26, 133, 255;--bs-btn-active-color: #000;--bs-btn-active-bg: #1a85ff;--bs-btn-active-border-color: #1a85ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #1a85ff;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #1a85ff;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #689f38;--bs-btn-border-color: #689f38;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #689f38;--bs-btn-hover-border-color: #689f38;--bs-btn-focus-shadow-rgb: 104, 159, 56;--bs-btn-active-color: #000;--bs-btn-active-bg: #689f38;--bs-btn-active-border-color: #689f38;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #689f38;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #689f38;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #00b4ff;--bs-btn-border-color: #00b4ff;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #00b4ff;--bs-btn-hover-border-color: #00b4ff;--bs-btn-focus-shadow-rgb: 0, 180, 255;--bs-btn-active-color: #000;--bs-btn-active-bg: #00b4ff;--bs-btn-active-border-color: #00b4ff;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #00b4ff;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #00b4ff;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #fdc935;--bs-btn-border-color: #fdc935;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #fdc935;--bs-btn-hover-border-color: #fdc935;--bs-btn-focus-shadow-rgb: 253, 201, 53;--bs-btn-active-color: #000;--bs-btn-active-bg: #fdc935;--bs-btn-active-border-color: #fdc935;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fdc935;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #fdc935;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #ff5267;--bs-btn-border-color: #ff5267;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ff5267;--bs-btn-hover-border-color: #ff5267;--bs-btn-focus-shadow-rgb: 255, 82, 103;--bs-btn-active-color: #000;--bs-btn-active-bg: #ff5267;--bs-btn-active-border-color: #ff5267;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff5267;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff5267;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 22, 113, 217;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.65625rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden}.collapsing.collapse-horizontal{width:0;height:auto}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:0.875rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: var(--bs-box-shadow);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #1a85ff;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 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(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.65625rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #1a85ff;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--bs-border-width)*-1)}.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:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(var(--bs-border-width)*-1)}.nav{--bs-nav-link-padding-x: 0.5rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:none;border:0}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(26,133,255,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 0;--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #1a85ff}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.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:700;color:var(--bs-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{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: 0.5rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 0.875rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25rem;--bs-navbar-toggler-padding-x: 0.75rem;--bs-navbar-toggler-font-size: 0.875rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color)}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.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(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important}.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]{--bs-navbar-color: rgba(255, 255, 255, 0.55);--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.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}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: transparent;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: 0;--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - 0);--bs-accordion-btn-padding-x: 0;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 0.75rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230a3566' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-accordion-body-padding-x: 0;--bs-accordion-body-padding-y: 0;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:0.875rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width)}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2376b6ff'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2376b6ff'%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{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:0.875rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #1a85ff;--bs-pagination-active-border-color: #1a85ff;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color)}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width)*-1)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.65625rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.65625rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #1a85ff;--bs-progress-bar-transition: width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg)}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #1a85ff;--bs-list-group-active-border-color: #1a85ff;display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(26, 133, 255, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: var(--bs-box-shadow-sm);--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0, -50px)}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.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}.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}.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}.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}.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}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 180px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.65625rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: 1;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-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(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.65625rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow: var(--bs-box-shadow);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:0.875rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-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(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0}.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}.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:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")*/}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")*/}.carousel-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 rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5}.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(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.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{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin:calc(-0.5*var(--bs-offcanvas-padding-y)) calc(-0.5*var(--bs-offcanvas-padding-x)) calc(-0.5*var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#000 !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#000 !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#000 !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(72, 157, 255, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(72, 157, 255, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(134, 178, 96, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(134, 178, 96, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(51, 195, 255, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(51, 195, 255, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(253, 212, 93, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(253, 212, 93, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(255, 117, 133, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 117, 133, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{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;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-none{-o-object-fit:none !important;object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.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(--bs-box-shadow) !important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm) !important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg) !important}.shadow-none{box-shadow:none !important}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-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:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-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{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.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:3rem !important}.column-gap-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.34375rem + 1.125vw) !important}.fs-2{font-size:calc(1.3rem + 0.6vw) !important}.fs-3{font-size:calc(1.278125rem + 0.3375vw) !important}.fs-4{font-size:calc(1.25625rem + 0.075vw) !important}.fs-5{font-size:1.09375rem !important}.fs-6{font-size:0.875rem !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{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{-webkit-user-select:all !important;-moz-user-select:all !important;user-select:all !important}.user-select-auto{-webkit-user-select:auto !important;-moz-user-select:auto !important;user-select:auto !important}.user-select-none{-webkit-user-select:none !important;-moz-user-select:none !important;user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-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(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-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(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-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(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-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(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-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(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-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(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-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(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-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}@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{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-sm-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-sm-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-sm-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-sm-none{-o-object-fit:none !important;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:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.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:3rem !important}.column-gap-sm-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-sm-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-sm-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-sm-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-sm-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-sm-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-md-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-md-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-md-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-md-none{-o-object-fit:none !important;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:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.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:3rem !important}.column-gap-md-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-md-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-md-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-md-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-md-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-md-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-lg-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-lg-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-lg-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-lg-none{-o-object-fit:none !important;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:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.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:3rem !important}.column-gap-lg-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-lg-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-lg-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-lg-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-lg-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-lg-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-xl-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-xl-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-xl-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-xl-none{-o-object-fit:none !important;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:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.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:3rem !important}.column-gap-xl-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-xl-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-xl-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-xl-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-xl-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-xl-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{-o-object-fit:contain !important;object-fit:contain !important}.object-fit-xxl-cover{-o-object-fit:cover !important;object-fit:cover !important}.object-fit-xxl-fill{-o-object-fit:fill !important;object-fit:fill !important}.object-fit-xxl-scale{-o-object-fit:scale-down !important;object-fit:scale-down !important}.object-fit-xxl-none{-o-object-fit:none !important;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:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.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:3rem !important}.column-gap-xxl-0{-moz-column-gap:0 !important;column-gap:0 !important}.column-gap-xxl-1{-moz-column-gap:.25rem !important;column-gap:.25rem !important}.column-gap-xxl-2{-moz-column-gap:.5rem !important;column-gap:.5rem !important}.column-gap-xxl-3{-moz-column-gap:1rem !important;column-gap:1rem !important}.column-gap-xxl-4{-moz-column-gap:1.5rem !important;column-gap:1.5rem !important}.column-gap-xxl-5{-moz-column-gap:3rem !important;column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}@media(min-width: 1200px){.fs-1{font-size:2.1875rem !important}.fs-2{font-size:1.75rem !important}.fs-3{font-size:1.53125rem !important}.fs-4{font-size:1.3125rem !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,[data-bs-theme=dark]{--elevation-0: 0 1px 1px 0 rgba(20, 23, 33, 0.8784313725), 0 0 1px 0 rgba(20, 23, 33, 0.8784313725);--elevation-0-inverted: 0 1px 1px 0 rgba(20, 23, 33, 0.0784313725), 0 0 1px 0 rgba(20, 23, 33, 0.3803921569);--elevation-1: 0 2px 4px -1px rgba(20, 23, 33, 0.3803921569), 0 1px 2px -1px rgba(20, 23, 33, 0.8784313725);--elevation-1-inverted: 0 2px 4px 1px rgba(20, 23, 33, 0.1215686275), 0 1px 2px 0 rgba(20, 23, 33, 0.1215686275);--elevation-2: 0 4px 8px 0 rgba(20, 23, 33, 0.3803921569), 0 2px 4px -1px rgba(20, 23, 33, 0.8784313725);--elevation-2-inverted: 0 4px 8px 0 rgba(20, 23, 33, 0.1215686275), 0 2px 4px -1px rgba(20, 23, 33, 0.0784313725);--elevation-3: 0 8px 12px 1px rgba(20, 23, 33, 0.3803921569), 0 4px 8px -1px rgba(20, 23, 33, 0.8784313725);--elevation-3-inverted: 0 8px 12px 1px rgba(20, 23, 33, 0.1215686275), 0 4px 8px -1px rgba(20, 23, 33, 0.0784313725);--elevation-4: 0 16px 32px 2px rgba(20, 23, 33, 0.3803921569), 0 8px 16px -2px rgba(20, 23, 33, 0.8784313725);--elevation-4-inverted: 0 16px 32px 2px rgba(20, 23, 33, 0.1215686275), 0 8px 16px -2px rgba(20, 23, 33, 0.0784313725);--primary-50: #373a44;--primary-50-inverted: white;--primary-100: #333640;--primary-100-inverted: #fafafb;--primary-200: #2f323c;--primary-200-inverted: #f5f6f6;--primary-300: #2b2e39;--primary-300-inverted: #f2f3f4;--primary-400: #272a35;--primary-400-inverted: #ebedee;--primary-500: #232632;--primary-500-inverted: #e6e8ea;--primary-600: #1f222e;--primary-600-inverted: #e2e4e6;--primary-700: #1b1e2a;--primary-700-inverted: #dddfe1;--primary-800: #181b26;--primary-800-inverted: #d8dadd;--primary-900: #141721;--primary-900-inverted: #d3d6d9;--text-placeholder: rgba(255, 255, 255, 0.3803921569);--text-placeholder-inverted: rgba(20, 23, 33, 0.3803921569);--text-secondary: rgba(255, 255, 255, 0.6);--text-secondary-inverted: rgba(20, 23, 33, 0.6);--text-primary: rgba(255, 255, 255, 0.8784313725);--text-primary-inverted: rgba(20, 23, 33, 0.8784313725);--text-primaryHover: white;--text-primaryHover-inverted: #141721;--text-disabled: rgba(255, 255, 255, 0.3019607843);--text-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--fill-subtle: rgba(255, 255, 255, 0.1019607843);--fill-subtle-inverted: rgba(20, 23, 33, 0.1019607843);--fill-secondary: rgba(255, 255, 255, 0.6);--fill-secondary-inverted: rgba(20, 23, 33, 0.6);--fill-primary: rgba(255, 255, 255, 0.8784313725);--fill-primary-inverted: rgba(20, 23, 33, 0.8784313725);--fill-enabled: rgba(255, 255, 255, 0.6);--fill-enabled-inverted: rgba(20, 23, 33, 0.6);--fill-active: rgba(255, 255, 255, 0.8784313725);--fill-active-inverted: rgba(20, 23, 33, 0.8784313725);--fill-hoverSelected: white;--fill-hoverSelected-inverted: #141721;--fill-disabled: rgba(255, 255, 255, 0.3019607843);--fill-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--border-subtleAlpha01: rgba(255, 255, 255, 0.1019607843);--border-subtleAlpha01-inverted: rgba(20, 23, 33, 0.1019607843);--border-subtleAlpha02: rgba(255, 255, 255, 0.1607843137);--border-subtleAlpha02-inverted: rgba(20, 23, 33, 0.1607843137);--border-subtleAlpha03: rgba(255, 255, 255, 0.2392156863);--border-subtleAlpha03-inverted: rgba(20, 23, 33, 0.2392156863);--border-enabled: rgba(255, 255, 255, 0.6);--border-enabled-inverted: rgba(20, 23, 33, 0.6);--border-hover: rgba(255, 255, 255, 0.8784313725);--border-hover-inverted: rgba(20, 23, 33, 0.8784313725);--border-disabled: rgba(255, 255, 255, 0.3019607843);--border-disabled-inverted: rgba(20, 23, 33, 0.3019607843);--border-selected: white;--border-selected-inverted: #141721;--border-selectedInverse: #141721;--border-selectedInverse-inverted: white;--stateOverlays-enabled: rgba(255, 255, 255, 0);--stateOverlays-enabled-inverted: rgba(20, 23, 33, 0);--stateOverlays-hover: rgba(255, 255, 255, 0.0392156863);--stateOverlays-hover-inverted: rgba(20, 23, 33, 0.0588235294);--stateOverlays-active: rgba(255, 255, 255, 0.0784313725);--stateOverlays-active-inverted: rgba(20, 23, 33, 0.1215686275);--stateOverlays-disabled: rgba(4, 19, 31, 0.1607843137);--stateOverlays-disabled-inverted: rgba(20, 23, 33, 0.1607843137);--stateOverlays-selected: #2b2e39;--stateOverlays-selected-inverted: #fafafb;--stateOverlays-selectedHover: rgba(255, 255, 255, 0.1607843137);--stateOverlays-selectedHover-inverted: rgba(20, 23, 33, 0.2392156863);--stateOverlays-selectedInverse: white;--stateOverlays-selectedInverse-inverted: #141721;--stateOverlays-selectedRange: rgba(255, 255, 255, 0.1019607843);--stateOverlays-selectedRange-inverted: rgba(20, 23, 33, 0.0784313725);--field-enabled: #2b2e39;--field-enabled-inverted: #fafafb;--field-hover: #373a44;--field-hover-inverted: white;--field-disabled: #272a35;--field-disabled-inverted: #f0f1f2;--status-success: #40d86e;--status-success-inverted: #26bf56;--status-error: #f56565;--status-error-inverted: #f03b3a;--status-information: #00b4ff;--status-information-inverted: #009eff;--status-warning: #ffc107;--status-warning-inverted: #f17c02;--focus: rgba(0, 133, 255, 0.6);--focus-inverted: rgba(0, 133, 255, 0.6);--surfaces-bg01: #232632;--surfaces-bg01-inverted: white;--surfaces-bg02: #1b1e2a;--surfaces-bg02-inverted: #f5f6f6;--surfaces-bg03: #141721;--surfaces-bg03-inverted: #e6e8ea;--categorical-01Cyan: #00b4ff;--categorical-01Cyan-inverted: #00b4ff;--categorical-02Orange: #ff9222;--categorical-02Orange-inverted: #ff9222;--categorical-03Purple: #3949ab;--categorical-03Purple-inverted: #3949ab;--categorical-04Red: #ff5267;--categorical-04Red-inverted: #ff5267;--categorical-05Teal: #08bdba;--categorical-05Teal-inverted: #08bdba;--categorical-06Amber: #fdc935;--categorical-06Amber-inverted: #fdc935;--categorical-07Green: #689f38;--categorical-07Green-inverted: #689f38;--categorical-08Purple: #976fd1;--categorical-08Purple-inverted: #976fd1;--categorical-09Pink: #f781bf;--categorical-09Pink-inverted: #f781bf;--categorical-10DarkGreen: #52733e;--categorical-10DarkGreen-inverted: #52733e;--sequentialCyan-100: #afe7f9;--sequentialCyan-100-inverted: #afe7f9;--sequentialCyan-200: #8bd0f6;--sequentialCyan-200-inverted: #8bd0f6;--sequentialCyan-300: #6cbaec;--sequentialCyan-300-inverted: #6cbaec;--sequentialCyan-400: #52a3dd;--sequentialCyan-400-inverted: #52a3dd;--sequentialCyan-500: #3b8dcb;--sequentialCyan-500-inverted: #3b8dcb;--sequentialCyan-600: #2777b7;--sequentialCyan-600-inverted: #2777b7;--sequentialCyan-700: #1661a2;--sequentialCyan-700-inverted: #1661a2;--sequentialCyan-800: #074c8c;--sequentialCyan-800-inverted: #074c8c;--sequentialCyan-900: #003875;--sequentialCyan-900-inverted: #003875;--sequentialOrange-100: #f9d8ac;--sequentialOrange-100-inverted: #f9d8ac;--sequentialOrange-200: #feb85b;--sequentialOrange-200-inverted: #feb85b;--sequentialOrange-300: #f09b32;--sequentialOrange-300-inverted: #f09b32;--sequentialOrange-400: #db811e;--sequentialOrange-400-inverted: #db811e;--sequentialOrange-500: #c76809;--sequentialOrange-500-inverted: #c76809;--sequentialOrange-600: #b05000;--sequentialOrange-600-inverted: #b05000;--sequentialOrange-700: #973a00;--sequentialOrange-700-inverted: #973a00;--sequentialOrange-800: #7e2400;--sequentialOrange-800-inverted: #7e2400;--sequentialOrange-900: #640d00;--sequentialOrange-900-inverted: #640d00;--sequentialIndigo-100: #dfd8fa;--sequentialIndigo-100-inverted: #dfd8fa;--sequentialIndigo-200: #c3c1ed;--sequentialIndigo-200-inverted: #c3c1ed;--sequentialIndigo-300: #aba8e0;--sequentialIndigo-300-inverted: #aba8e0;--sequentialIndigo-400: #9390d2;--sequentialIndigo-400-inverted: #9390d2;--sequentialIndigo-500: #7a79c4;--sequentialIndigo-500-inverted: #7a79c4;--sequentialIndigo-600: #6163b5;--sequentialIndigo-600-inverted: #6163b5;--sequentialIndigo-700: #474ea6;--sequentialIndigo-700-inverted: #474ea6;--sequentialIndigo-800: #2a3994;--sequentialIndigo-800-inverted: #2a3994;--sequentialIndigo-900: #002680;--sequentialIndigo-900-inverted: #002680;--sequentialYellow-100: #fff7cd;--sequentialYellow-100-inverted: #fff7cd;--sequentialYellow-200: #ffed9b;--sequentialYellow-200-inverted: #ffed9b;--sequentialYellow-300: #ffe16a;--sequentialYellow-300-inverted: #ffe16a;--sequentialYellow-400: #ffd545;--sequentialYellow-400-inverted: #ffd545;--sequentialYellow-500: #ffc107;--sequentialYellow-500-inverted: #ffc107;--sequentialYellow-600: #dba005;--sequentialYellow-600-inverted: #dba005;--sequentialYellow-700: #b78103;--sequentialYellow-700-inverted: #b78103;--sequentialYellow-800: #936402;--sequentialYellow-800-inverted: #936402;--sequentialYellow-900: #7a4f01;--sequentialYellow-900-inverted: #7a4f01;--sequentialTeal-100: #a5eae8;--sequentialTeal-100-inverted: #a5eae8;--sequentialTeal-200: #7dd5d3;--sequentialTeal-200-inverted: #7dd5d3;--sequentialTeal-300: #5ebfbc;--sequentialTeal-300-inverted: #5ebfbc;--sequentialTeal-400: #44a8a6;--sequentialTeal-400-inverted: #44a8a6;--sequentialTeal-500: #2e9190;--sequentialTeal-500-inverted: #2e9190;--sequentialTeal-600: #1b7b7a;--sequentialTeal-600-inverted: #1b7b7a;--sequentialTeal-700: #0c6565;--sequentialTeal-700-inverted: #0c6565;--sequentialTeal-800: #025050;--sequentialTeal-800-inverted: #025050;--sequentialTeal-900: #003b3c;--sequentialTeal-900-inverted: #003b3c;--sequentialRed-100: #f8d6da;--sequentialRed-100-inverted: #f8d6da;--sequentialRed-200: #fcb6ba;--sequentialRed-200-inverted: #fcb6ba;--sequentialRed-300: #f8989b;--sequentialRed-300-inverted: #f8989b;--sequentialRed-400: #ed7b7f;--sequentialRed-400-inverted: #ed7b7f;--sequentialRed-500: #dd6065;--sequentialRed-500-inverted: #dd6065;--sequentialRed-600: #c9474c;--sequentialRed-600-inverted: #c9474c;--sequentialRed-700: #b22f36;--sequentialRed-700-inverted: #b22f36;--sequentialRed-800: #981822;--sequentialRed-800-inverted: #981822;--sequentialRed-900: #7d000f;--sequentialRed-900-inverted: #7d000f;--surfaces-bg-card: #232632;--surfaces-bg-card-inverted: #F5F6F6;--bs-primary-rgb: #ffffffe0;--bs-secondary-color: #ffffff99;--bs-nav-link-color: #ffffff99;--bs-form-valid-color: #40d86eff;--bs-form-invalid-color: #f56565ff;--bs-body-bg: #141721;--bs-tooltip-bg: white;--bs-tooltip-color: rgba(20, 23, 33, 0.8784313725)}[data-bs-theme=light]{--elevation-0: 0 1px 1px 0 rgba(20, 23, 33, 0.0784313725), 0 0 1px 0 rgba(20, 23, 33, 0.3803921569);--elevation-0-inverted: 0 1px 1px 0 rgba(20, 23, 33, 0.8784313725), 0 0 1px 0 rgba(20, 23, 33, 0.8784313725);--elevation-1: 0 2px 4px 1px rgba(20, 23, 33, 0.1215686275), 0 1px 2px 0 rgba(20, 23, 33, 0.1215686275);--elevation-1-inverted: 0 2px 4px -1px rgba(20, 23, 33, 0.3803921569), 0 1px 2px -1px rgba(20, 23, 33, 0.8784313725);--elevation-2: 0 4px 8px 0 rgba(20, 23, 33, 0.1215686275), 0 2px 4px -1px rgba(20, 23, 33, 0.0784313725);--elevation-2-inverted: 0 4px 8px 0 rgba(20, 23, 33, 0.3803921569), 0 2px 4px -1px rgba(20, 23, 33, 0.8784313725);--elevation-3: 0 8px 12px 1px rgba(20, 23, 33, 0.1215686275), 0 4px 8px -1px rgba(20, 23, 33, 0.0784313725);--elevation-3-inverted: 0 8px 12px 1px rgba(20, 23, 33, 0.3803921569), 0 4px 8px -1px rgba(20, 23, 33, 0.8784313725);--elevation-4: 0 16px 32px 2px rgba(20, 23, 33, 0.1215686275), 0 8px 16px -2px rgba(20, 23, 33, 0.0784313725);--elevation-4-inverted: 0 16px 32px 2px rgba(20, 23, 33, 0.3803921569), 0 8px 16px -2px rgba(20, 23, 33, 0.8784313725);--primary-50: white;--primary-50-inverted: #373a44;--primary-100: #fafafb;--primary-100-inverted: #333640;--primary-200: #f5f6f6;--primary-200-inverted: #2f323c;--primary-300: #f2f3f4;--primary-300-inverted: #2b2e39;--primary-400: #ebedee;--primary-400-inverted: #272a35;--primary-500: #e6e8ea;--primary-500-inverted: #232632;--primary-600: #e2e4e6;--primary-600-inverted: #1f222e;--primary-700: #dddfe1;--primary-700-inverted: #1b1e2a;--primary-800: #d8dadd;--primary-800-inverted: #181b26;--primary-900: #d3d6d9;--primary-900-inverted: #141721;--text-placeholder: rgba(20, 23, 33, 0.3803921569);--text-placeholder-inverted: rgba(255, 255, 255, 0.3803921569);--text-secondary: rgba(20, 23, 33, 0.6);--text-secondary-inverted: rgba(255, 255, 255, 0.6);--text-primary: rgba(20, 23, 33, 0.8784313725);--text-primary-inverted: rgba(255, 255, 255, 0.8784313725);--text-primaryHover: #141721;--text-primaryHover-inverted: white;--text-disabled: rgba(20, 23, 33, 0.3019607843);--text-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--fill-subtle: rgba(20, 23, 33, 0.1019607843);--fill-subtle-inverted: rgba(255, 255, 255, 0.1019607843);--fill-secondary: rgba(20, 23, 33, 0.6);--fill-secondary-inverted: rgba(255, 255, 255, 0.6);--fill-primary: rgba(20, 23, 33, 0.8784313725);--fill-primary-inverted: rgba(255, 255, 255, 0.8784313725);--fill-enabled: rgba(20, 23, 33, 0.6);--fill-enabled-inverted: rgba(255, 255, 255, 0.6);--fill-active: rgba(20, 23, 33, 0.8784313725);--fill-active-inverted: rgba(255, 255, 255, 0.8784313725);--fill-hoverSelected: #141721;--fill-hoverSelected-inverted: white;--fill-disabled: rgba(20, 23, 33, 0.3019607843);--fill-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--border-subtleAlpha01: rgba(20, 23, 33, 0.1019607843);--border-subtleAlpha01-inverted: rgba(255, 255, 255, 0.1019607843);--border-subtleAlpha02: rgba(20, 23, 33, 0.1607843137);--border-subtleAlpha02-inverted: rgba(255, 255, 255, 0.1607843137);--border-subtleAlpha03: rgba(20, 23, 33, 0.2392156863);--border-subtleAlpha03-inverted: rgba(255, 255, 255, 0.2392156863);--border-enabled: rgba(20, 23, 33, 0.6);--border-enabled-inverted: rgba(255, 255, 255, 0.6);--border-hover: rgba(20, 23, 33, 0.8784313725);--border-hover-inverted: rgba(255, 255, 255, 0.8784313725);--border-disabled: rgba(20, 23, 33, 0.3019607843);--border-disabled-inverted: rgba(255, 255, 255, 0.3019607843);--border-selected: #141721;--border-selected-inverted: white;--border-selectedInverse: white;--border-selectedInverse-inverted: #141721;--stateOverlays-enabled: rgba(20, 23, 33, 0);--stateOverlays-enabled-inverted: rgba(255, 255, 255, 0);--stateOverlays-hover: rgba(20, 23, 33, 0.0588235294);--stateOverlays-hover-inverted: rgba(255, 255, 255, 0.0392156863);--stateOverlays-active: rgba(20, 23, 33, 0.1215686275);--stateOverlays-active-inverted: rgba(255, 255, 255, 0.0784313725);--stateOverlays-disabled: rgba(20, 23, 33, 0.1607843137);--stateOverlays-disabled-inverted: rgba(4, 19, 31, 0.1607843137);--stateOverlays-selected: #fafafb;--stateOverlays-selected-inverted: #2b2e39;--stateOverlays-selectedHover: rgba(20, 23, 33, 0.2392156863);--stateOverlays-selectedHover-inverted: rgba(255, 255, 255, 0.1607843137);--stateOverlays-selectedInverse: #141721;--stateOverlays-selectedInverse-inverted: white;--stateOverlays-selectedRange: rgba(20, 23, 33, 0.0784313725);--stateOverlays-selectedRange-inverted: rgba(255, 255, 255, 0.1019607843);--field-enabled: #fafafb;--field-enabled-inverted: #2b2e39;--field-hover: white;--field-hover-inverted: #373a44;--field-disabled: #f0f1f2;--field-disabled-inverted: #272a35;--status-success: #26bf56;--status-success-inverted: #40d86e;--status-error: #f03b3a;--status-error-inverted: #f56565;--status-information: #009eff;--status-information-inverted: #00b4ff;--status-warning: #f17c02;--status-warning-inverted: #ffc107;--focus: rgba(0, 133, 255, 0.6);--focus-inverted: rgba(0, 133, 255, 0.6);--surfaces-bg01: white;--surfaces-bg01-inverted: #232632;--surfaces-bg02: #f5f6f6;--surfaces-bg02-inverted: #1b1e2a;--surfaces-bg03: #e6e8ea;--surfaces-bg03-inverted: #141721;--categorical-01Cyan: #00b4ff;--categorical-01Cyan-inverted: #00b4ff;--categorical-02Orange: #ff9222;--categorical-02Orange-inverted: #ff9222;--categorical-03Purple: #3949ab;--categorical-03Purple-inverted: #3949ab;--categorical-04Red: #ff5267;--categorical-04Red-inverted: #ff5267;--categorical-05Teal: #08bdba;--categorical-05Teal-inverted: #08bdba;--categorical-06Amber: #fdc935;--categorical-06Amber-inverted: #fdc935;--categorical-07Green: #689f38;--categorical-07Green-inverted: #689f38;--categorical-08Purple: #976fd1;--categorical-08Purple-inverted: #976fd1;--categorical-09Pink: #f781bf;--categorical-09Pink-inverted: #f781bf;--categorical-10DarkGreen: #52733e;--categorical-10DarkGreen-inverted: #52733e;--sequentialCyan-100: #afe7f9;--sequentialCyan-100-inverted: #afe7f9;--sequentialCyan-200: #8bd0f6;--sequentialCyan-200-inverted: #8bd0f6;--sequentialCyan-300: #6cbaec;--sequentialCyan-300-inverted: #6cbaec;--sequentialCyan-400: #52a3dd;--sequentialCyan-400-inverted: #52a3dd;--sequentialCyan-500: #3b8dcb;--sequentialCyan-500-inverted: #3b8dcb;--sequentialCyan-600: #2777b7;--sequentialCyan-600-inverted: #2777b7;--sequentialCyan-700: #1661a2;--sequentialCyan-700-inverted: #1661a2;--sequentialCyan-800: #074c8c;--sequentialCyan-800-inverted: #074c8c;--sequentialCyan-900: #003875;--sequentialCyan-900-inverted: #003875;--sequentialOrange-100: #f9d8ac;--sequentialOrange-100-inverted: #f9d8ac;--sequentialOrange-200: #feb85b;--sequentialOrange-200-inverted: #feb85b;--sequentialOrange-300: #f09b32;--sequentialOrange-300-inverted: #f09b32;--sequentialOrange-400: #db811e;--sequentialOrange-400-inverted: #db811e;--sequentialOrange-500: #c76809;--sequentialOrange-500-inverted: #c76809;--sequentialOrange-600: #b05000;--sequentialOrange-600-inverted: #b05000;--sequentialOrange-700: #973a00;--sequentialOrange-700-inverted: #973a00;--sequentialOrange-800: #7e2400;--sequentialOrange-800-inverted: #7e2400;--sequentialOrange-900: #640d00;--sequentialOrange-900-inverted: #640d00;--sequentialIndigo-100: #dfd8fa;--sequentialIndigo-100-inverted: #dfd8fa;--sequentialIndigo-200: #c3c1ed;--sequentialIndigo-200-inverted: #c3c1ed;--sequentialIndigo-300: #aba8e0;--sequentialIndigo-300-inverted: #aba8e0;--sequentialIndigo-400: #9390d2;--sequentialIndigo-400-inverted: #9390d2;--sequentialIndigo-500: #7a79c4;--sequentialIndigo-500-inverted: #7a79c4;--sequentialIndigo-600: #6163b5;--sequentialIndigo-600-inverted: #6163b5;--sequentialIndigo-700: #474ea6;--sequentialIndigo-700-inverted: #474ea6;--sequentialIndigo-800: #2a3994;--sequentialIndigo-800-inverted: #2a3994;--sequentialIndigo-900: #002680;--sequentialIndigo-900-inverted: #002680;--sequentialYellow-100: #fff7cd;--sequentialYellow-100-inverted: #fff7cd;--sequentialYellow-200: #ffed9b;--sequentialYellow-200-inverted: #ffed9b;--sequentialYellow-300: #ffe16a;--sequentialYellow-300-inverted: #ffe16a;--sequentialYellow-400: #ffd545;--sequentialYellow-400-inverted: #ffd545;--sequentialYellow-500: #ffc107;--sequentialYellow-500-inverted: #ffc107;--sequentialYellow-600: #dba005;--sequentialYellow-600-inverted: #dba005;--sequentialYellow-700: #b78103;--sequentialYellow-700-inverted: #b78103;--sequentialYellow-800: #936402;--sequentialYellow-800-inverted: #936402;--sequentialYellow-900: #7a4f01;--sequentialYellow-900-inverted: #7a4f01;--sequentialTeal-100: #a5eae8;--sequentialTeal-100-inverted: #a5eae8;--sequentialTeal-200: #7dd5d3;--sequentialTeal-200-inverted: #7dd5d3;--sequentialTeal-300: #5ebfbc;--sequentialTeal-300-inverted: #5ebfbc;--sequentialTeal-400: #44a8a6;--sequentialTeal-400-inverted: #44a8a6;--sequentialTeal-500: #2e9190;--sequentialTeal-500-inverted: #2e9190;--sequentialTeal-600: #1b7b7a;--sequentialTeal-600-inverted: #1b7b7a;--sequentialTeal-700: #0c6565;--sequentialTeal-700-inverted: #0c6565;--sequentialTeal-800: #025050;--sequentialTeal-800-inverted: #025050;--sequentialTeal-900: #003b3c;--sequentialTeal-900-inverted: #003b3c;--sequentialRed-100: #f8d6da;--sequentialRed-100-inverted: #f8d6da;--sequentialRed-200: #fcb6ba;--sequentialRed-200-inverted: #fcb6ba;--sequentialRed-300: #f8989b;--sequentialRed-300-inverted: #f8989b;--sequentialRed-400: #ed7b7f;--sequentialRed-400-inverted: #ed7b7f;--sequentialRed-500: #dd6065;--sequentialRed-500-inverted: #dd6065;--sequentialRed-600: #c9474c;--sequentialRed-600-inverted: #c9474c;--sequentialRed-700: #b22f36;--sequentialRed-700-inverted: #b22f36;--sequentialRed-800: #981822;--sequentialRed-800-inverted: #981822;--sequentialRed-900: #7d000f;--sequentialRed-900-inverted: #7d000f;--surfaces-bg-card: #F5F6F6;--surfaces-bg-card-inverted: #232632;--bs-primary-rgb: #141721e0;--bs-secondary-color: #14172199;--bs-nav-link-color: #14172199;--bs-form-valid-color: #26bf56ff;--bs-form-invalid-color: #f03b3aff;--bs-body-bg: white;--bs-tooltip-bg: #141721;--bs-tooltip-color: rgba(255, 255, 255, 0.8784313725)}[data-bs-theme=dark]{--bs-primary: #1b0734;--bs-secondary: #808080;--bs-success: #222222;--bs-danger: #be3636;--bs-info: #163960;--bs-dark: #2a2a2a;--bs-light: #333333;--bs-primary-rgb: 27, 7, 52;--bs-secondary-rgb: 128, 128, 128;--bs-success-rgb: 34, 34, 34;--bs-danger-rgb: 190, 54, 54;--bs-info-rgb: 22, 57, 96;--bs-dark-rgb: 42, 42, 42;--bs-light-rgb: 51, 51, 51}[data-bs-theme=light]{--bs-primary: #1b0734;--bs-secondary: #808080;--bs-success: #222222;--bs-danger: #be3636;--bs-info: #163960;--bs-dark: #2a2a2a;--bs-light: #333333;--bs-primary-rgb: 27, 7, 52;--bs-secondary-rgb: 128, 128, 128;--bs-success-rgb: 34, 34, 34;--bs-danger-rgb: 190, 54, 54;--bs-info-rgb: 22, 57, 96;--bs-dark-rgb: 42, 42, 42;--bs-light-rgb: 51, 51, 51}h1,.h1{font-size:32px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.128px;line-height:40px;color:var(--text-primary)}h2,.h2{font-size:24px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.096px;line-height:32px;color:var(--text-primary)}h3,.h3,legend{font-size:20px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:0px;line-height:28px;color:var(--text-primary)}h4,.h4{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;color:var(--text-primary)}h5,.h5{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;font-size:14px;color:var(--text-primary)}h6,.h6{font-size:16px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.016px;line-height:20px;font-size:12px;color:var(--text-primary)}p,label,ul,li,blockquote{color:var(--text-secondary)}.text-muted{color:var(--text-subtle)}.text-primary{color:var(--text-primary) !important}.text-secondary{color:var(--text-secondary) !important}blockquote{border-left:.25rem var(--text-secondary) solid;margin-bottom:.5rem;padding-left:.25rem}hr{border-bottom:1px solid var(--border-subtleAlpha01);width:100%}.btn{display:inline-flex;justify-content:center;align-items:center;width:-moz-fit-content;width:fit-content;height:32px}.btn-large{height:40px}.btn-primary{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0);transition:box-shadow .2s}.btn-primary:enabled,.btn-primary.enabled{border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:active,.btn-primary.active{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-active-inverted), var(--stateOverlays-active-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:hover,.btn-primary.hover{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-hover-inverted), var(--stateOverlays-hover-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-1)}.btn-primary:focus,.btn-primary.focus{color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:1px solid rgba(0,0,0,0);box-shadow:var(--elevation-0);outline:2px solid var(--focus-color)}.btn-primary:disabled,.btn-primary.disabled{color:var(--text-disabled-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-disabled-inverted), var(--stateOverlays-disabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-primary:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary-inverted);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:linear-gradient(var(--stateOverlays-enabled-inverted), var(--stateOverlays-enabled-inverted)),var(--fill-active);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-0)}.btn-secondary{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-enabled);box-shadow:var(--elevation-0);transition:box-shadow .2s}.btn-secondary:enabled,.btn-secondary.enabled{border:1px solid var(--border-enabled);box-shadow:var(--elevation-0)}.btn-secondary:active,.btn-secondary.active{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-active);border:1px solid var(--border-selected);box-shadow:var(--elevation-0)}.btn-secondary:hover,.btn-secondary.hover{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-hover);border:1px solid var(--border-hover);box-shadow:var(--elevation-1)}.btn-secondary:focus,.btn-secondary.focus{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-hover);box-shadow:var(--elevation-0);outline:2px solid var(--focus-color)}.btn-secondary:disabled,.btn-secondary.disabled{color:var(--text-disabled);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-disabled);box-shadow:var(--elevation-0)}.btn-secondary:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid var(--border-enabled);box-shadow:var(--elevation-0)}.btn-tertiary,.btn-link{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None;transition:box-shadow .2s}.btn-tertiary:enabled,.btn-tertiary.enabled,.btn-link:enabled,.btn-link.enabled{border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:active,.btn-tertiary.active,.btn-link:active,.btn-link.active{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-active);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:hover,.btn-tertiary.hover,.btn-link:hover,.btn-link.hover{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-hover);border:0 solid rgba(0,0,0,0);box-shadow:var(--elevation-1)}.btn-tertiary:focus,.btn-tertiary.focus,.btn-link:focus,.btn-link.focus{color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:1px solid rgba(0,0,0,0);box-shadow:None;outline:2px solid var(--focus-color)}.btn-tertiary:disabled,.btn-tertiary.disabled,.btn-link:disabled,.btn-link.disabled{color:var(--text-disabled);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary:focus:not(:focus-visible,:disabled,.disabled),.btn-link:focus:not(:focus-visible,:disabled,.disabled){color:var(--text-primary);font-size:14px;text-decoration:none;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;font-size:14px;text-decoration:underline;font-weight:600;font-style:normal;font-stretch:normal;letter-spacing:-0.056px;line-height:16px;background:var(--stateOverlays-enabled);border:0 solid rgba(0,0,0,0);box-shadow:None}.btn-tertiary,.btn-tertiary:disabled,.btn-tertiary.disabled,.btn-link,.btn-link:disabled,.btn-link.disabled{text-decoration:underline}.accordion{width:100%}.accordion-body{display:flex;flex-direction:column;gap:.5rem}.accordion-item{color:var(--text-primary);border-bottom:1px solid var(--border-subtleAlpha01)}.accordion-item .nav-link{padding:.5rem;color:var(--text-secondary)}.accordion-item .nav-link:last-child{margin-bottom:.75rem}.accordion-item .nav-link:active,.accordion-item .nav-link.active{background:var(--stateOverlays-active);color:var(--text-primary)}.accordion-item .nav-link:hover,.accordion-item .nav-link.hover{background:var(--stateOverlays-selectedHover);color:var(--text-primary)}.accordion-item .nav-link:disabled,.accordion-item .nav-link.disabled{color:var(--text-disabled)}.accordion-item .nav-link:focus:not(:focus-visible,:disabled,.disabled){background:var(--stateOverlays-active);color:var(--text-primary)}.accordion-button{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary);text-transform:uppercase;border:none;box-shadow:none}.accordion-button::after{filter:contrast(0);opacity:.4}.accordion-button:not(.collapsed){color:var(--text-primary);background-color:rgba(0,0,0,0);box-shadow:none}.accordion-button:not(.collapsed)::after{filter:contrast(0);opacity:1}.accordion-button:hover,.accordion-button.hover{color:var(--text-primary)}.accordion-button:hover::after,.accordion-button.hover::after{opacity:1}.accordion-button:focus,.accordion-button.focus{border:none;box-shadow:none}.card{background:var(--surfaces-bg-card);border:none;box-shadow:var(--elevation-1);width:100%;height:100%;overflow:auto;padding:1rem}.card-nav:hover,.card-nav.hover{background:var(--field-enabled);box-shadow:var(--elevation-2);transform:translate3d(0, -0.5rem, 0);will-change:transform}.card-title,.card-header{color:var(--text-primary)}.card-subtitle{color:var(--text-secondary)}.card-text{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary)}.card-text:last-child{margin-bottom:.5rem}.navbar{background:var(--surfaces-bg02) !important}.navbar .nav-link{padding:0;align-items:center;display:flex;height:4rem;justify-content:center;color:var(--text-secondary)}.navbar .nav-link:active,.navbar .nav-link.active{color:var(--text-primary)}.form-check{transition:all 150ms ease 0s;margin-bottom:12px;line-height:16px;min-height:auto;padding-left:28px}.form-check-inline{margin-right:12px}.form-check-input{margin:0;position:relative;border-color:var(--border-enabled);border-radius:0;color:var(--fill-active);width:16px;height:16px;outline:none;background-color:rgba(0,0,0,0);background-size:auto}.form-check-input:checked{background-color:rgba(0,0,0,0);border-color:var(--border-enabled);color:var(--fill-active)}.form-check-input[type=radio]{background-image:none}.form-check-input[type=radio]:checked::after{position:absolute;content:"";background-color:var(--fill-active);border-radius:50%;width:8px;height:8px;top:50%;left:50%;transform:translate(-50%, -50%)}.form-check-input:hover,.form-check-input.hover{border-color:var(--border-hover)}.form-check-input:active,.form-check-input.active{border-color:var(--border-selected)}.form-check-input:disabled,.form-check-input.disabled{border-color:var(--border-disabled)}.form-check-input:focus,.form-check-input.focus{border-color:var(--border-selected);box-shadow:none}.form-check-input:hover{border-color:var(--border-hover)}.form-check .form-check-input{margin-left:-24px}.form-check-label{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary)}.form-check-lg{line-height:20px;min-height:auto;padding-left:32px}.form-check-lg .form-check-input{width:20px;height:20px;border-width:2px;margin-left:-28px}.form-check-lg .form-check-label{line-height:20px}.form-check.disabled .form-check-label{color:var(--text-disabled)}.form-switch{display:flex;gap:8px}.form-switch .form-check-input{background-color:var(--fill-subtle);border:1px solid var(--border-enabled);border-radius:16px;height:16px;width:32px}.form-switch .form-check-input:focus-visible,.form-switch .form-check-input.focus-visible{box-shadow:0 0 0 2px var(--focus)}.form-switch .form-check-input:disabled,.form-switch .form-check-input.disabled{border-color:var(--border-disabled)}.form-switch .form-check-input:checked{background-color:var(--fill-active);border:1px solid var(--border-selected)}.form-switch .form-check-input:checked:disabled,.form-switch .form-check-input:checked.disabled{background-color:var(--fill-subtle);border-color:var(--border-disabled)}[data-bs-theme=light] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=light] .form-switch .form-check-input:disabled,[data-bs-theme=light] .form-switch .form-check-input.disabled{--bs-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(20, 23, 33, 0.3019607843)'/%3e%3c/svg%3e")}[data-bs-theme=light] .form-switch .form-check-input:checked[type=checkbox]:not(:disabled){--bs-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='white'/%3e%3c/svg%3e")}[data-bs-theme=light] .form-switch .form-check-input:focus,[data-bs-theme=light] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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(20, 23, 33, 0.6)'/%3e%3c/svg%3e")}[data-bs-theme=dark] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=dark] .form-switch .form-check-input:disabled,[data-bs-theme=dark] .form-switch .form-check-input.disabled{--bs-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(255, 255, 255, 0.3019607843)'/%3e%3c/svg%3e")}[data-bs-theme=dark] .form-switch .form-check-input:checked[type=checkbox]:not(:disabled){--bs-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=''/%3e%3c/svg%3e")}[data-bs-theme=dark] .form-switch .form-check-input:focus,[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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(255, 255, 255, 0.6)'/%3e%3c/svg%3e")}[data-bs-theme=light] [data-bs-theme=dark] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(255, 255, 255, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-switch .form-check-input:disabled,[data-bs-theme=light] [data-bs-theme=dark] .form-switch .form-check-input.disabled{--bs-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(255, 255, 255, 0.3019607843)'/%3e%3c/svg%3e")}[data-bs-theme=light] [data-bs-theme=dark] .form-switch .form-check-input:checked[type=checkbox]:not(:disabled){--bs-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=''/%3e%3c/svg%3e")}[data-bs-theme=light] [data-bs-theme=dark] .form-switch .form-check-input:focus,[data-bs-theme=light] [data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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(255, 255, 255, 0.6)'/%3e%3c/svg%3e")}[data-bs-theme=dark] [data-bs-theme=light] .form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3Csvg width='8' height='7' viewBox='0 0 8 7' xmlns='http://www.w3.org/2000/svg' data-testid='checkmark-icon'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.5 1.25L6.25 0L2.5 3.75L1.25 2.5L0 3.75L2.5 6.25L7.5 1.25Z' fill='rgba(20, 23, 33, 0.8784313725)'/%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-switch .form-check-input:disabled,[data-bs-theme=dark] [data-bs-theme=light] .form-switch .form-check-input.disabled{--bs-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(20, 23, 33, 0.3019607843)'/%3e%3c/svg%3e")}[data-bs-theme=dark] [data-bs-theme=light] .form-switch .form-check-input:checked[type=checkbox]:not(:disabled){--bs-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=''/%3e%3c/svg%3e")}[data-bs-theme=dark] [data-bs-theme=light] .form-switch .form-check-input:focus,[data-bs-theme=dark] [data-bs-theme=light] .form-switch .form-check-input:not(:checked):not(:focus){--bs-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(20, 23, 33, 0.6)'/%3e%3c/svg%3e")}.form-control,.input-group-text{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;background-color:var(--field-enabled);color:var(--text-primary);padding:.5rem;box-shadow:var(--elevation-0);border:none}.form-control::-moz-placeholder, .input-group-text::-moz-placeholder{color:var(--text-placeholder)}.form-control::placeholder,.input-group-text::placeholder{color:var(--text-placeholder)}.form-control:focus,.form-control.focus,.input-group-text:focus,.input-group-text.focus{background-color:var(--field-hover);color:var(--text-primary);box-shadow:0 0 0 2px var(--focus) inset}.form-control:hover,.form-control.hover,.input-group-text:hover,.input-group-text.hover{background-color:var(--field-hover)}.form-control:disabled,.form-control.disabled,.input-group-text:disabled,.input-group-text.disabled{background-color:var(--field-disabled);color:var(--text-disabled)}.form-control:focus-visible,.form-control.focus-visible,.input-group-text:focus-visible,.input-group-text.focus-visible{outline:none}.form-control.is-invalid{box-shadow:0 0 0 2px var(--status-error) inset;border:none}.form-control.is-invalid:focus,.form-control.is-invalid.focus{box-shadow:0 0 0 2px var(--status-error) inset}.form-control.is-valid{box-shadow:0 0 0 2px var(--status-success) inset}.form-control.is-valid:focus,.form-control.is-valid.focus{box-shadow:0 0 0 2px var(--status-success) inset}[data-bs-theme=light] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2340d86e' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=light] [data-bs-theme=dark] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f56565' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-control.is-valid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='M421-311.463 690.537-581l-34.845-34.23L421-380.153 302.539-498.615l-33.846 34.23L421-311.463Zm59.067 211.462q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%2326bf56' d='m421-298 283-283-46-45-237 237-120-120-45 45 165 166Zm59 218q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}[data-bs-theme=dark] [data-bs-theme=light] .form-control.is-invalid{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='M331.539-299.539 480-448.001l148.461 148.462 32-32L511.999-480l148.462-148.461-32-32L480-511.999 331.539-660.461l-32 32L448.001-480 299.539-331.539l32 32Zm148.528 199.538q-78.221 0-147.397-29.92-69.176-29.92-120.989-81.71-51.814-51.791-81.747-120.936-29.933-69.146-29.933-147.366 0-78.836 29.92-148.204 29.92-69.369 81.71-120.682 51.791-51.314 120.936-81.247 69.146-29.933 147.366-29.933 78.836 0 148.204 29.92 69.369 29.92 120.682 81.21 51.314 51.291 81.247 120.629 29.933 69.337 29.933 148.173 0 78.221-29.92 147.397-29.92 69.176-81.21 120.989-51.291 51.814-120.629 81.747-69.337 29.933-148.173 29.933ZM480-145.385q139.692 0 237.154-97.769Q814.615-340.923 814.615-480q0-139.692-97.461-237.154Q619.692-814.615 480-814.615q-139.077 0-236.846 97.461Q145.385-619.692 145.385-480q0 139.077 97.769 236.846T480-145.385ZM480-480Z'%3E%3C/path%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 -960 960 960'%3E%3Cpath fill='%23f03b3a' d='m330-288 150-150 150 150 42-42-150-150 150-150-42-42-150 150-150-150-42 42 150 150-150 150 42 42ZM480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Zm0-60q142 0 241-99.5T820-480q0-142-99-241t-241-99q-141 0-240.5 99T140-480q0 141 99.5 240.5T480-140Zm0-340Z'%3E%3C/path%3E%3C/svg%3E")}.form-label{font-size:14px;text-decoration:none;font-weight:400;font-style:normal;font-stretch:normal;letter-spacing:-0.112px;line-height:16px;color:var(--text-secondary);margin-bottom:12px;width:100%}.tooltip{display:flex;justify-content:center;align-items:center;box-shadow:var(--elevation-2-inverted)}.tooltip-inner{font-size:12px;text-decoration:none;font-weight:300;font-style:normal;font-stretch:normal;letter-spacing:.024px;line-height:16px;text-align:left}.nav-tabs{align-items:flex-start;align-self:stretch;flex-wrap:nowrap;border-bottom:1px solid var(--border-subtleAlpha01);display:flex;gap:1rem}.nav-tabs .nav-link{color:var(--text-secondary);height:2rem;padding:0 0 .5rem;margin-bottom:-1px}.nav-tabs .nav-link:active,.nav-tabs .nav-link.active{border-bottom:1px solid var(--border-selected);color:var(--text-primary)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link.hover{border-bottom:1px solid var(--border-hover);color:var(--text-primaryHover)}.nav-tabs .nav-link:focus-visible,.nav-tabs .nav-link.focus-visible{border-bottom:1px solid var(--focus);box-shadow:none;color:var(--text-primaryHover)}.nav-tabs .nav-link:disabled,.nav-tabs .nav-link.disabled{color:var(--text-disabled)}.qb-container-bg-01{background-color:var(--surfaces-bg01);padding:40px;width:100%}.qb-container-bg-02{background-color:var(--surfaces-bg02);padding:40px;width:100%}.qb-container-bg-03{background-color:var(--surfaces-bg03);padding:40px;width:100%}
diff --git a/vizro-core/src/vizro/static/js/models/range_slider.js b/vizro-core/src/vizro/static/js/models/range_slider.js
index 5eb1892aa..8aafdde7f 100644
--- a/vizro-core/src/vizro/static/js/models/range_slider.js
+++ b/vizro-core/src/vizro/static/js/models/range_slider.js
@@ -17,6 +17,8 @@ function update_range_slider_values(
trigger_id =
dash_clientside.callback_context.triggered[0]["prop_id"].split(".")[0];
}
+
+ // text form component is the trigger
if (
trigger_id === `${self_data["id"]}_start_value` ||
trigger_id === `${self_data["id"]}_end_value`
@@ -24,21 +26,36 @@ function update_range_slider_values(
if (isNaN(start) || isNaN(end)) {
return dash_clientside.no_update;
}
- [start_text_value, end_text_value] = [start, end];
+ return [start, end, [start, end], [start, end]];
+
+ // slider component is the trigger
} else if (trigger_id === self_data["id"]) {
- [start_text_value, end_text_value] = [slider[0], slider[1]];
- } else {
- [start_text_value, end_text_value] =
- input_store !== null ? input_store : [slider[0], slider[1]];
+ return [slider[0], slider[1], slider, slider];
}
-
- start_value = Math.min(start_text_value, end_text_value);
- end_value = Math.max(start_text_value, end_text_value);
- start_value = Math.max(self_data["min"], start_value);
- end_value = Math.min(self_data["max"], end_value);
- slider_value = [start_value, end_value];
-
- return [start_value, end_value, slider_value, [start_value, end_value]];
+ // on_page_load is the trigger
+ if (input_store === null) {
+ return [
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ slider,
+ ];
+ }
+ if (
+ slider[0] === start &&
+ input_store[0] === start &&
+ slider[1] === end &&
+ input_store[1] === end
+ ) {
+ // To prevent filter_action to be triggered after on_page_load
+ return [
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ ];
+ }
+ return [input_store[0], input_store[1], input_store, input_store];
}
window.dash_clientside = {
diff --git a/vizro-core/src/vizro/static/js/models/slider.js b/vizro-core/src/vizro/static/js/models/slider.js
index bc572cffe..1b15d78ae 100644
--- a/vizro-core/src/vizro/static/js/models/slider.js
+++ b/vizro-core/src/vizro/static/js/models/slider.js
@@ -6,20 +6,31 @@ function update_slider_values(start, slider, input_store, self_data) {
trigger_id =
dash_clientside.callback_context.triggered[0]["prop_id"].split(".")[0];
}
+
+ // text form component is the trigger
if (trigger_id === `${self_data["id"]}_end_value`) {
if (isNaN(start)) {
return dash_clientside.no_update;
}
- end_value = start;
+ return [start, start, start];
+
+ // slider component is the trigger
} else if (trigger_id === self_data["id"]) {
- end_value = slider;
- } else {
- end_value = input_store !== null ? input_store : self_data["min"];
+ return [slider, slider, slider];
}
-
- end_value = Math.min(Math.max(self_data["min"], end_value), self_data["max"]);
-
- return [end_value, end_value, end_value];
+ // on_page_load is the trigger
+ if (input_store === null) {
+ return [dash_clientside.no_update, dash_clientside.no_update, slider];
+ }
+ if (slider === start && start === input_store) {
+ // To prevent filter_action to be triggered after on_page_load
+ return [
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ dash_clientside.no_update,
+ ];
+ }
+ return [input_store, input_store, input_store];
}
window.dash_clientside = {
diff --git a/vizro-core/src/vizro/tables/_dash_table.py b/vizro-core/src/vizro/tables/_dash_table.py
index 4335b68ef..f3b93f16b 100644
--- a/vizro-core/src/vizro/tables/_dash_table.py
+++ b/vizro-core/src/vizro/tables/_dash_table.py
@@ -31,17 +31,17 @@ def dash_data_table(data_frame: pd.DataFrame, **kwargs: Any) -> dash_table.DataT
"columns": [{"name": col, "id": col} for col in data_frame.columns],
"style_as_list_view": True,
"style_cell": {"position": "static"},
- "style_data": {"border_bottom": "1px solid var(--border-subtle-alpha-01)", "height": "40px"},
+ "style_data": {"border_bottom": "1px solid var(--border-subtleAlpha01)", "height": "40px"},
"style_header": {
- "border_bottom": "1px solid var(--state-overlays-selected-hover)",
- "border_top": "1px solid var(--main-container-bg-color)",
+ "border_bottom": "1px solid var(--stateOverlays-selectedHover)",
+ "border_top": "1px solid var(--right-side-bg)",
"height": "32px",
},
"style_data_conditional": [
{
"if": {"state": "active"},
- "backgroundColor": "var(--state-overlays-selected)",
- "border": "1px solid var(--state-overlays-selected)",
+ "backgroundColor": "var(--stateOverlays-selected)",
+ "border": "1px solid var(--stateOverlays-selected)",
}
],
}
diff --git a/vizro-core/tests/e2e/screenshots/main_kpi_card_component_library.png b/vizro-core/tests/e2e/screenshots/main_kpi_card_component_library.png
new file mode 100644
index 000000000..bc9550578
Binary files /dev/null and b/vizro-core/tests/e2e/screenshots/main_kpi_card_component_library.png differ
diff --git a/vizro-core/tests/e2e/test_component_library.py b/vizro-core/tests/e2e/test_component_library.py
new file mode 100644
index 000000000..553a6878c
--- /dev/null
+++ b/vizro-core/tests/e2e/test_component_library.py
@@ -0,0 +1,89 @@
+import dash_bootstrap_components as dbc
+import pandas as pd
+from dash import Dash, html
+from e2e_asserts import assert_image_equal, make_screenshot_and_paths
+
+from vizro.figures.library import kpi_card, kpi_card_reference
+
+df_kpi = pd.DataFrame(
+ {
+ "Actual": [100, 200, 700],
+ "Reference": [100, 300, 500],
+ "Category": ["A", "B", "C"],
+ }
+)
+
+example_cards = [
+ kpi_card(data_frame=df_kpi, value_column="Actual", title="KPI with value"),
+ kpi_card(
+ data_frame=df_kpi,
+ value_column="Actual",
+ title="KPI with aggregation",
+ agg_func="median",
+ ),
+ kpi_card(
+ data_frame=df_kpi,
+ value_column="Actual",
+ title="KPI formatted",
+ value_format="${value:.2f}",
+ ),
+ kpi_card(
+ data_frame=df_kpi,
+ value_column="Actual",
+ title="KPI with icon",
+ icon="shopping_cart",
+ ),
+]
+
+example_reference_cards = [
+ kpi_card_reference(
+ data_frame=df_kpi,
+ value_column="Actual",
+ reference_column="Reference",
+ title="KPI ref. (pos)",
+ ),
+ kpi_card_reference(
+ data_frame=df_kpi,
+ value_column="Actual",
+ reference_column="Reference",
+ agg_func="median",
+ title="KPI ref. (neg)",
+ ),
+ kpi_card_reference(
+ data_frame=df_kpi,
+ value_column="Actual",
+ reference_column="Reference",
+ title="KPI ref. formatted",
+ value_format="{value}€",
+ reference_format="{delta}€ vs. last year ({reference}€)",
+ ),
+ kpi_card_reference(
+ data_frame=df_kpi,
+ value_column="Actual",
+ reference_column="Reference",
+ title="KPI ref. with icon",
+ icon="shopping_cart",
+ ),
+]
+
+
+def test_kpi_card_component_library(dash_duo, request):
+ app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
+ app.layout = dbc.Container(
+ [
+ html.H1(children="KPI Cards"),
+ dbc.Stack(
+ children=[
+ dbc.Row([dbc.Col(kpi_card) for kpi_card in example_cards]),
+ dbc.Row([dbc.Col(kpi_card) for kpi_card in example_reference_cards]),
+ ],
+ gap=4,
+ ),
+ ]
+ )
+ dash_duo.start_server(app)
+ dash_duo.wait_for_page(timeout=20)
+ dash_duo.wait_for_element("div[class='card-kpi card']")
+ result_image_path, expected_image_path = make_screenshot_and_paths(dash_duo.driver, request.node.name)
+ assert_image_equal(result_image_path, expected_image_path)
+ assert dash_duo.get_logs() == [], "browser console should contain no error"
diff --git a/vizro-core/tests/integration/test_examples.py b/vizro-core/tests/integration/test_examples.py
index a983469c3..1acdd4372 100644
--- a/vizro-core/tests/integration/test_examples.py
+++ b/vizro-core/tests/integration/test_examples.py
@@ -1,4 +1,3 @@
-# ruff: noqa: F403, F405
import os
import runpy
from pathlib import Path
@@ -40,17 +39,15 @@ def dashboard(request, monkeypatch):
examples_path = Path(__file__).parents[2] / "examples"
-# Ignore deprecation warning until this is solved: https://github.com/plotly/dash/issues/2590
-# The `features` examples do add_type, which ideally we would clean up afterwards to restore vizro.models to
-# its previous state. Since we don't currently do this, `hatch run test` fails.
-# This is difficult to fix fully by un-importing vizro.models though, since we use `import vizro.models as vm` - see
-# https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module.
-@pytest.mark.filterwarnings("ignore:HTTPResponse.getheader():DeprecationWarning")
# Ignore as it doesn't affect the test run
@pytest.mark.filterwarnings("ignore::pytest.PytestUnhandledThreadExceptionWarning")
@pytest.mark.filterwarnings("ignore:unclosed file:ResourceWarning")
# Ignore for lower bounds because of plotly==5.12.0
@pytest.mark.filterwarnings("ignore:The behavior of DatetimeProperties.to_pydatetime is deprecated:FutureWarning")
+# The `features` examples do add_type, which ideally we would clean up afterwards to restore vizro.models to
+# its previous state. Since we don't currently do this, `hatch run test` fails.
+# This is difficult to fix fully by un-importing vizro.models though, since we use `import vizro.models as vm` - see
+# https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module.
@pytest.mark.parametrize(
"example_path, version",
[
diff --git a/vizro-core/tests/tests_utils/e2e_asserts.py b/vizro-core/tests/tests_utils/e2e_asserts.py
new file mode 100644
index 000000000..e16eb40eb
--- /dev/null
+++ b/vizro-core/tests/tests_utils/e2e_asserts.py
@@ -0,0 +1,69 @@
+import shutil
+from pathlib import Path
+
+import cv2
+import imutils
+from hamcrest import assert_that, equal_to
+
+
+def _compare_images(expected_image, result_image):
+ """Comparison process."""
+ # Subtract two images
+ difference = cv2.subtract(expected_image, result_image)
+ # Splitting image into separate channels
+ blue, green, red = cv2.split(difference)
+ # Counting non-zero pixels and comparing it to zero
+ assert_that(cv2.countNonZero(blue), equal_to(0), reason="Blue channel is different")
+ assert_that(cv2.countNonZero(green), equal_to(0), reason="Green channel is different")
+ assert_that(cv2.countNonZero(red), equal_to(0), reason="Red channel is different")
+
+
+def _create_image_difference(expected_image, result_image):
+ """Creates new image with diff of images comparison."""
+ # Calculate the difference between the two images
+ diff = cv2.absdiff(expected_image, result_image)
+ # Convert image to grayscale
+ gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
+ for i in range(0, 3):
+ # Dilation of the image
+ dilated = cv2.dilate(gray.copy(), None, iterations=i + 1)
+ # Apply threshold to the dilated image
+ (t_var, thresh) = cv2.threshold(dilated, 3, 255, cv2.THRESH_BINARY)
+ # Calculate difference contours for the image
+ cnts = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
+ cnts = imutils.grab_contours(cnts)
+ for contour in cnts:
+ # Calculate bounding rectangles around detected contour
+ (x, y, width, height) = cv2.boundingRect(contour)
+ # Draw red rectangle around difference area
+ cv2.rectangle(result_image, (x, y), (x + width, y + height), (0, 0, 255), 2)
+ return result_image
+
+
+def make_screenshot_and_paths(browserdriver, request_node_name):
+ """Creates image paths and makes screenshot during the test run."""
+ result_image_path = f"{request_node_name}_branch.png"
+ expected_image_path = f"tests/e2e/screenshots/{request_node_name.replace('test', 'main')}.png"
+ browserdriver.save_screenshot(result_image_path)
+ return result_image_path, expected_image_path
+
+
+def assert_image_equal(result_image_path, expected_image_path):
+ """Comparison logic and diff files creation."""
+ expected_image = cv2.imread(expected_image_path)
+ expected_image_name = Path(expected_image_path).name
+ result_image = cv2.imread(result_image_path)
+ try:
+ _compare_images(expected_image, result_image)
+ # Deleting created branch image to leave only failed for github artifacts
+ Path(result_image_path).unlink()
+ except AssertionError as exc:
+ # Copy created branch image to the one with the name from main for easier replacement in the repo
+ shutil.copy(result_image_path, expected_image_name)
+ diff = _create_image_difference(expected_image=expected_image, result_image=result_image)
+ # Writing image with differences to a new file
+ cv2.imwrite(f"{result_image_path}_difference_from_main.png", diff)
+ raise AssertionError("pictures are not the same") from exc
+ except cv2.error as exc:
+ shutil.copy(result_image_path, expected_image_name)
+ raise cv2.error("pictures has different sizes") from exc
diff --git a/vizro-core/tests/unit/vizro/actions/_action_loop/test_get_action_loop_components.py b/vizro-core/tests/unit/vizro/actions/_action_loop/test_get_action_loop_components.py
index 9e649188d..55838f186 100644
--- a/vizro-core/tests/unit/vizro/actions/_action_loop/test_get_action_loop_components.py
+++ b/vizro-core/tests/unit/vizro/actions/_action_loop/test_get_action_loop_components.py
@@ -1,8 +1,9 @@
"""Unit tests for vizro.actions._action_loop._get_action_loop_components file."""
import pytest
-from asserts import assert_component_equal
+from asserts import STRIP_ALL, assert_component_equal
from dash import dcc, html
+from dash._utils import stringify_id
import vizro.models as vm
import vizro.plotly.express as px
@@ -27,7 +28,7 @@ def gateway_components(request):
components = request.param
actions_chain_ids = [model_manager[component].actions[0].id for component in components]
return [
- dcc.Store(id={"type": "gateway_input", "trigger_id": actions_chain_id}, data=f"{actions_chain_id}")
+ dcc.Store(id={"type": "gateway_input", "trigger_id": actions_chain_id}, data=actions_chain_id)
for actions_chain_id in actions_chain_ids
]
@@ -153,11 +154,26 @@ def test_all_action_loop_components(
result = _get_action_loop_components()
expected = html.Div(
id="action_loop_components_div",
- children=fundamental_components
- + gateway_components
- + action_trigger_components
- + [action_trigger_actions_id_component]
- + [trigger_to_actions_chain_mapper_component],
+ children=[
+ *fundamental_components,
+ *gateway_components,
+ *action_trigger_components,
+ action_trigger_actions_id_component,
+ trigger_to_actions_chain_mapper_component,
+ ],
)
- assert_component_equal(result, expected)
+ # Data in these dcc.Stores is arbitrarily order. Sort in advance to ensure that assert_component_equal
+ # is order-agnostic for their data.
+ for key in ("action_trigger_actions_id", "trigger_to_actions_chain_mapper"):
+ result[key].data = sorted(result[key].data)
+ expected[key].data = sorted(expected[key].data)
+
+ # Validate the action_loop_components_div wrapper.
+ assert_component_equal(result, expected, keys_to_strip=STRIP_ALL)
+
+ # Order of dcc.Stores inside div wrapper is arbitrary so sort by stringified id to do order-agnostic comparison.
+ assert_component_equal(
+ sorted(result.children, key=lambda component: stringify_id(component.id)),
+ sorted(expected.children, key=lambda component: stringify_id(component.id)),
+ )
diff --git a/vizro-core/tests/unit/vizro/actions/_callback_mapping/test_get_action_callback_mapping.py b/vizro-core/tests/unit/vizro/actions/_callback_mapping/test_get_action_callback_mapping.py
index 27adbb223..c32b8e1c7 100644
--- a/vizro-core/tests/unit/vizro/actions/_callback_mapping/test_get_action_callback_mapping.py
+++ b/vizro-core/tests/unit/vizro/actions/_callback_mapping/test_get_action_callback_mapping.py
@@ -9,6 +9,7 @@
from vizro import Vizro
from vizro.actions import export_data, filter_interaction
from vizro.actions._callback_mapping._get_action_callback_mapping import _get_action_callback_mapping
+from vizro.managers import model_manager
from vizro.models.types import capture
@@ -185,7 +186,7 @@ class TestCallbackMapping:
],
)
def test_action_callback_mapping_inputs(self, action_id, action_callback_inputs_expected):
- result = _get_action_callback_mapping(action_id=action_id, argument="inputs")
+ result = _get_action_callback_mapping(action=model_manager[action_id], argument="inputs")
assert result == action_callback_inputs_expected
@pytest.mark.parametrize(
@@ -242,14 +243,14 @@ def test_action_callback_mapping_inputs(self, action_id, action_callback_inputs_
indirect=["action_callback_outputs_expected"],
)
def test_action_callback_mapping_outputs(self, action_id, action_callback_outputs_expected):
- result = _get_action_callback_mapping(action_id=action_id, argument="outputs")
+ result = _get_action_callback_mapping(action=model_manager[action_id], argument="outputs")
assert result == action_callback_outputs_expected
@pytest.mark.parametrize(
"export_data_outputs_expected", [("scatter_chart", "scatter_chart_2", "vizro_table")], indirect=True
)
def test_export_data_no_targets_set_mapping_outputs(self, export_data_outputs_expected):
- result = _get_action_callback_mapping(action_id="export_data_action", argument="outputs")
+ result = _get_action_callback_mapping(action=model_manager["export_data_action"], argument="outputs")
assert result == export_data_outputs_expected
@@ -266,7 +267,7 @@ def test_export_data_no_targets_set_mapping_outputs(self, export_data_outputs_ex
def test_export_data_targets_set_mapping_outputs(
self, config_for_testing_all_components_with_actions, export_data_outputs_expected
):
- result = _get_action_callback_mapping(action_id="export_data_action", argument="outputs")
+ result = _get_action_callback_mapping(action=model_manager["export_data_action"], argument="outputs")
assert result == export_data_outputs_expected
@@ -274,7 +275,9 @@ def test_export_data_targets_set_mapping_outputs(
"export_data_components_expected", [("scatter_chart", "scatter_chart_2", "vizro_table")], indirect=True
)
def test_export_data_no_targets_set_mapping_components(self, export_data_components_expected):
- result_components = _get_action_callback_mapping(action_id="export_data_action", argument="components")
+ result_components = _get_action_callback_mapping(
+ action=model_manager["export_data_action"], argument="components"
+ )
assert_component_equal(result_components, export_data_components_expected)
@pytest.mark.parametrize(
@@ -290,11 +293,13 @@ def test_export_data_no_targets_set_mapping_components(self, export_data_compone
def test_export_data_targets_set_mapping_components(
self, config_for_testing_all_components_with_actions, export_data_components_expected
):
- result_components = _get_action_callback_mapping(action_id="export_data_action", argument="components")
+ result_components = _get_action_callback_mapping(
+ action=model_manager["export_data_action"], argument="components"
+ )
assert_component_equal(result_components, export_data_components_expected)
def test_known_action_unknown_argument(self):
- result = _get_action_callback_mapping(action_id="export_data_action", argument="unknown-argument")
+ result = _get_action_callback_mapping(action=model_manager["export_data_action"], argument="unknown-argument")
assert result == {}
# "export_data_custom_action" represents a unique scenario within custom actions, where the function's name
@@ -305,5 +310,5 @@ def test_known_action_unknown_argument(self):
"argument, expected", [("inputs", {}), ("outputs", {}), ("components", []), ("unknown-argument", {})]
)
def test_custom_action_mapping(self, action_id, argument, expected):
- result = _get_action_callback_mapping(action_id=action_id, argument=argument)
+ result = _get_action_callback_mapping(action=model_manager[action_id], argument=argument)
assert result == expected
diff --git a/vizro-core/tests/unit/vizro/actions/conftest.py b/vizro-core/tests/unit/vizro/actions/conftest.py
index 902ca042f..3b7bc5337 100644
--- a/vizro-core/tests/unit/vizro/actions/conftest.py
+++ b/vizro-core/tests/unit/vizro/actions/conftest.py
@@ -1,4 +1,3 @@
-import pandas as pd
import pytest
import vizro.models as vm
@@ -25,37 +24,11 @@ def iris():
return px.data.iris()
-@pytest.fixture
-def gapminder_dynamic_first_n_last_n_function(gapminder):
- return lambda first_n=None, last_n=None: (
- pd.concat([gapminder[:first_n], gapminder[-last_n:]])
- if last_n
- else gapminder[:first_n]
- if first_n
- else gapminder
- )
-
-
-@pytest.fixture
-def box_params():
- return {"x": "continent", "y": "lifeExp", "custom_data": ["continent"]}
-
-
@pytest.fixture
def box_chart(gapminder_2007, box_params):
return px.box(gapminder_2007, **box_params)
-@pytest.fixture
-def box_chart_dynamic_data_frame(box_params):
- return px.box("gapminder_dynamic_first_n_last_n", **box_params)
-
-
-@pytest.fixture
-def scatter_params():
- return {"x": "gdpPercap", "y": "lifeExp"}
-
-
@pytest.fixture
def scatter_chart(gapminder_2007, scatter_params):
return px.scatter(gapminder_2007, **scatter_params)
@@ -71,11 +44,6 @@ def scatter_matrix_chart(iris, scatter_matrix_params):
return px.scatter_matrix(iris, **scatter_matrix_params)
-@pytest.fixture
-def scatter_chart_dynamic_data_frame(scatter_params):
- return px.scatter("gapminder_dynamic_first_n_last_n", **scatter_params)
-
-
@pytest.fixture
def target_scatter_filtered_continent(request, gapminder_2007, scatter_params):
continent = request.param
@@ -105,21 +73,6 @@ def managers_one_page_two_graphs_one_button(box_chart, scatter_chart):
Vizro._pre_build()
-@pytest.fixture
-def managers_one_page_two_graphs_with_dynamic_data(box_chart_dynamic_data_frame, scatter_chart_dynamic_data_frame):
- """Instantiates a simple model_manager and data_manager with a page, two graph models and the button component."""
- vm.Page(
- id="test_page",
- title="My first dashboard",
- components=[
- vm.Graph(id="box_chart", figure=box_chart_dynamic_data_frame),
- vm.Graph(id="scatter_chart", figure=scatter_chart_dynamic_data_frame),
- vm.Button(id="button"),
- ],
- )
- Vizro._pre_build()
-
-
@pytest.fixture
def managers_one_page_two_graphs_one_table_one_aggrid_one_button(
box_chart, scatter_chart, dash_data_table_with_id, ag_grid_with_id
diff --git a/vizro-core/tests/unit/vizro/conftest.py b/vizro-core/tests/unit/vizro/conftest.py
index cba2bccc7..dd15c9fa4 100644
--- a/vizro-core/tests/unit/vizro/conftest.py
+++ b/vizro-core/tests/unit/vizro/conftest.py
@@ -1,5 +1,6 @@
"""Fixtures to be shared across several tests."""
+import pandas as pd
import plotly.graph_objects as go
import pytest
@@ -20,6 +21,17 @@ def stocks():
return px.data.stocks()
+@pytest.fixture
+def gapminder_dynamic_first_n_last_n_function(gapminder):
+ return lambda first_n=None, last_n=None: (
+ pd.concat([gapminder[:first_n], gapminder[-last_n:]])
+ if last_n
+ else gapminder[:first_n]
+ if first_n
+ else gapminder
+ )
+
+
@pytest.fixture
def standard_px_chart(gapminder):
return px.scatter(
@@ -33,6 +45,26 @@ def standard_px_chart(gapminder):
)
+@pytest.fixture
+def scatter_params():
+ return {"x": "gdpPercap", "y": "lifeExp"}
+
+
+@pytest.fixture
+def scatter_chart_dynamic_data_frame(scatter_params):
+ return px.scatter("gapminder_dynamic_first_n_last_n", **scatter_params)
+
+
+@pytest.fixture
+def box_params():
+ return {"x": "continent", "y": "lifeExp", "custom_data": ["continent"]}
+
+
+@pytest.fixture
+def box_chart_dynamic_data_frame(box_params):
+ return px.box("gapminder_dynamic_first_n_last_n", **box_params)
+
+
@pytest.fixture
def standard_ag_grid(gapminder):
return dash_ag_grid(data_frame=gapminder)
@@ -88,6 +120,21 @@ def page_2():
return vm.Page(title="Page 2", components=[vm.Button()])
+@pytest.fixture
+def managers_one_page_two_graphs_with_dynamic_data(box_chart_dynamic_data_frame, scatter_chart_dynamic_data_frame):
+ """Instantiates a simple model_manager and data_manager with a page, two graph models and the button component."""
+ vm.Page(
+ id="test_page",
+ title="My first dashboard",
+ components=[
+ vm.Graph(id="box_chart", figure=box_chart_dynamic_data_frame),
+ vm.Graph(id="scatter_chart", figure=scatter_chart_dynamic_data_frame),
+ vm.Button(id="button"),
+ ],
+ )
+ Vizro._pre_build()
+
+
@pytest.fixture()
def vizro_app():
"""Fixture to instantiate Vizro/Dash app.
diff --git a/vizro-core/tests/unit/vizro/models/_components/form/test_range_slider.py b/vizro-core/tests/unit/vizro/models/_components/form/test_range_slider.py
index e0c9a9f13..4879aafc3 100644
--- a/vizro-core/tests/unit/vizro/models/_components/form/test_range_slider.py
+++ b/vizro-core/tests/unit/vizro/models/_components/form/test_range_slider.py
@@ -48,7 +48,7 @@ def expected_range_slider_default():
persistence_type="session",
className="slider-text-input-field",
),
- dcc.Store(id="range_slider_input_store", storage_type="session", data=[None, None]),
+ dcc.Store(id="range_slider_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
@@ -105,7 +105,7 @@ def expected_range_slider_with_optional():
persistence_type="session",
className="slider-text-input-field",
),
- dcc.Store(id="range_slider_input_store", storage_type="session", data=[0, 10]),
+ dcc.Store(id="range_slider_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
diff --git a/vizro-core/tests/unit/vizro/models/_components/form/test_slider.py b/vizro-core/tests/unit/vizro/models/_components/form/test_slider.py
index 56d2c5f24..92b34429e 100755
--- a/vizro-core/tests/unit/vizro/models/_components/form/test_slider.py
+++ b/vizro-core/tests/unit/vizro/models/_components/form/test_slider.py
@@ -35,7 +35,7 @@ def expected_slider():
persistence_type="session",
className="slider-text-input-field",
),
- dcc.Store(id="slider_id_input_store", storage_type="session", data=5.0),
+ dcc.Store(id="slider_id_input_store", storage_type="session"),
],
className="slider-text-input-container",
),
diff --git a/vizro-core/tests/unit/vizro/models/_components/test_button.py b/vizro-core/tests/unit/vizro/models/_components/test_button.py
index fa793e443..1118c8de6 100644
--- a/vizro-core/tests/unit/vizro/models/_components/test_button.py
+++ b/vizro-core/tests/unit/vizro/models/_components/test_button.py
@@ -16,14 +16,28 @@ def test_create_default_button(self):
assert hasattr(button, "id")
assert button.type == "button"
assert button.text == "Click me!"
+ assert button.href == ""
assert button.actions == []
- @pytest.mark.parametrize("text", ["Test", 123, 1.23, True, """# Header""", """Hello
"""])
- def test_create_button_with_optional(self, text):
- button = vm.Button(text=text)
- assert hasattr(button, "id")
+ @pytest.mark.parametrize(
+ "text, href",
+ [
+ ("Test", "/page_1_reference"),
+ ("Test", "https://www.google.de/"),
+ (123, "/"),
+ ("""# Header""", "/"),
+ (1.23, "/"),
+ ("""Hello
""", "/"),
+ (True, "/"),
+ ],
+ )
+ def test_create_button_with_optional(self, text, href):
+ button = vm.Button(id="button-id", text=text, href=href)
+
+ assert button.id == "button-id"
assert button.type == "button"
assert button.text == str(text)
+ assert button.href == href
assert button.actions == []
def test_set_action_via_validator(self):
@@ -33,7 +47,12 @@ def test_set_action_via_validator(self):
class TestBuildMethod:
- def test_button_build(self):
+ def test_button_build_wo_href(self):
button = vm.Button(id="button_id", text="My text").build()
- expected = dbc.Button(id="button_id", children="My text")
+ expected = dbc.Button(id="button_id", children="My text", href="", target="_top")
+ assert_component_equal(button, expected)
+
+ def test_button_build_with_href(self):
+ button = vm.Button(id="button_id", text="My text", href="https://www.google.com").build()
+ expected = dbc.Button(id="button_id", children="My text", href="https://www.google.com", target="_top")
assert_component_equal(button, expected)
diff --git a/vizro-core/tests/unit/vizro/models/_components/test_card.py b/vizro-core/tests/unit/vizro/models/_components/test_card.py
index 44c9d24ab..9b4274653 100755
--- a/vizro-core/tests/unit/vizro/models/_components/test_card.py
+++ b/vizro-core/tests/unit/vizro/models/_components/test_card.py
@@ -77,8 +77,8 @@ def test_card_build_wo_href(self):
("Text to test card", "Text to test card"),
("", ""),
(
- """![](assets/images/icons/content/hypotheses.svg#icon-top)""",
- "![](assets/images/icons/content/hypotheses.svg#icon-top)",
+ """![](assets/images/icons/content/hypotheses.svg)""",
+ "![](assets/images/icons/content/hypotheses.svg)",
),
("""Code block: ```python print(1)```""", "Code block: ```python print(1)```"),
("""[Example page](/test_page)""", "[Example page](/test_page)"),
diff --git a/vizro-core/tests/unit/vizro/models/_components/test_tabs.py b/vizro-core/tests/unit/vizro/models/_components/test_tabs.py
index d2f8bb39f..7a83dcfc0 100644
--- a/vizro-core/tests/unit/vizro/models/_components/test_tabs.py
+++ b/vizro-core/tests/unit/vizro/models/_components/test_tabs.py
@@ -1,6 +1,6 @@
"""Unit tests for vizro.models.Container."""
-import dash_mantine_components as dmc
+import dash_bootstrap_components as dbc
import pytest
from asserts import assert_component_equal
from dash import html
@@ -41,42 +41,20 @@ def test_tabs_build(self, containers):
# We want to test the component itself but not all its children
assert_component_equal(
result,
- dmc.Tabs(id="tabs-id", value="container-1", persistence=True, persistence_type="session", className="tabs"),
+ dbc.Tabs(id="tabs-id", persistence=True, persistence_type="session"),
keys_to_strip={"children"},
)
# We want to test the children created in the Tabs.build but not e.g. the
# vm.Container.build() as it's tested elsewhere already
assert_component_equal(
- result.children,
- [dmc.TabsList(), dmc.TabsPanel(value="container-1"), dmc.TabsPanel(value="container-2")],
- keys_to_strip={"children", "className"},
- )
- # So we go down the tree and ignore the children selectively
- assert_component_equal(
- result.children[0],
- dmc.TabsList(
- children=[
- dmc.Tab(value="container-1", children="Title-1", className="tab-title"),
- dmc.Tab(value="container-2", children="Title-2", className="tab-title"),
- ],
- className="tabs-list",
- ),
- )
- # This one removes the need for duplication of tests as the output is similar
- assert_component_equal(
- result.children[1:],
- [
- dmc.TabsPanel(className="tabs-panel", value="container-1"),
- dmc.TabsPanel(className="tabs-panel", value="container-2"),
- ],
- keys_to_strip={"children"},
+ result.children, [dbc.Tab(label="Title-1"), dbc.Tab(label="Title-2")], keys_to_strip={"children"}
)
# We still check that the html.Div for the Containers are created, but we don't need to check its content
assert_component_equal(
- [tab.children.children for tab in result.children[1:]],
+ [tab.children for tab in result.children],
[
- [html.Div(id="container-1", className="page-component-container")],
- [html.Div(id="container-2", className="page-component-container")],
+ html.Div(id="container-1", className="page-component-container"),
+ html.Div(id="container-2", className="page-component-container"),
],
keys_to_strip={"children"},
)
diff --git a/vizro-core/tests/unit/vizro/models/_controls/test_filter.py b/vizro-core/tests/unit/vizro/models/_controls/test_filter.py
index 3f3d909e9..2b64666e9 100644
--- a/vizro-core/tests/unit/vizro/models/_controls/test_filter.py
+++ b/vizro-core/tests/unit/vizro/models/_controls/test_filter.py
@@ -4,11 +4,12 @@
import pandas as pd
import pytest
from asserts import assert_component_equal
+from dash import dcc
import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
-from vizro.managers import model_manager
+from vizro.managers import data_manager, model_manager
from vizro.models._action._actions_chain import ActionsChain
from vizro.models._controls.filter import Filter, _filter_between, _filter_isin
from vizro.models.types import CapturedCallable
@@ -52,6 +53,32 @@ def managers_column_only_exists_in_some():
Vizro._pre_build()
+@pytest.fixture
+def target_to_data_frame():
+ return {
+ "column_numerical_exists_1": pd.DataFrame(
+ {
+ "column_numerical": [1, 2],
+ }
+ ),
+ "column_numerical_exists_2": pd.DataFrame(
+ {
+ "column_numerical": [2, 3],
+ }
+ ),
+ "column_categorical_exists_1": pd.DataFrame(
+ {
+ "column_categorical": ["a", "b"],
+ }
+ ),
+ "column_categorical_exists_2": pd.DataFrame(
+ {
+ "column_categorical": ["b", "c"],
+ }
+ ),
+ }
+
+
class TestFilterFunctions:
@pytest.mark.parametrize(
"data, value, expected",
@@ -219,6 +246,167 @@ def test_filter_isin_date(self, data, value, expected):
pd.testing.assert_series_equal(result, expected)
+class TestFilterStaticMethods:
+ """Tests static methods of the Filter class."""
+
+ @pytest.mark.parametrize(
+ "data_columns, expected",
+ [
+ ([[]], []),
+ ([["A", "B", "A"]], ["A", "B"]),
+ ([[1, 2, 1]], [1, 2]),
+ ([[1.1, 2.2, 1.1]], [1.1, 2.2]),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ datetime(2024, 1, 1),
+ ]
+ ],
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ ],
+ ),
+ ([[], []], []),
+ ([["A"], []], ["A"]),
+ ([[], ["A"]], ["A"]),
+ ([["A"], ["B"]], ["A", "B"]),
+ ([["A", "B"], ["B", "C"]], ["A", "B", "C"]),
+ ],
+ )
+ def test_get_options(self, data_columns, expected):
+ targeted_data = pd.DataFrame({f"target_{i}": pd.Series(data) for i, data in enumerate(data_columns)})
+ result = Filter._get_options(targeted_data)
+ assert result == expected
+
+ @pytest.mark.parametrize(
+ "data_columns, current_value, expected",
+ [
+ ([[]], None, []),
+ ([[]], "ALL", []),
+ ([[]], ["ALL", "A"], ["A"]),
+ ([["A"]], ["ALL", "B"], ["A", "B"]),
+ ([[]], "A", ["A"]),
+ ([[]], ["A", "B"], ["A", "B"]),
+ ([["A"]], "B", ["A", "B"]),
+ ([["A"]], ["B", "C"], ["A", "B", "C"]),
+ ([[1]], 2, [1, 2]),
+ ([[1]], [2, 3], [1, 2, 3]),
+ ([[1.1]], 2.2, [1.1, 2.2]),
+ ([[1.1]], [2.2, 3.3], [1.1, 2.2, 3.3]),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ ]
+ ],
+ datetime(2024, 1, 2),
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ ],
+ ),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ ]
+ ],
+ [
+ datetime(2024, 1, 2),
+ datetime(2024, 1, 3),
+ ],
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ datetime(2024, 1, 3),
+ ],
+ ),
+ ],
+ )
+ def test_get_options_with_current_value(self, data_columns, current_value, expected):
+ targeted_data = pd.DataFrame({f"target_{i}": pd.Series(data) for i, data in enumerate(data_columns)})
+ result = Filter._get_options(targeted_data, current_value)
+ assert result == expected
+
+ @pytest.mark.parametrize(
+ "data_columns, expected",
+ [
+ ([[1, 2, 1]], (1, 2)),
+ ([[1.1, 2.2, 1.1]], (1.1, 2.2)),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ datetime(2024, 1, 1),
+ ]
+ ],
+ (
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ ),
+ ),
+ ([[1], []], (1, 1)),
+ ([[1, 2], []], (1, 2)),
+ ([[1, 2], [2, 3]], (1, 3)),
+ ],
+ )
+ def test_get_min_max(self, data_columns, expected):
+ targeted_data = pd.DataFrame({f"target_{i}": pd.Series(data) for i, data in enumerate(data_columns)})
+ result = Filter._get_min_max(targeted_data)
+ assert result == expected
+
+ @pytest.mark.parametrize(
+ "data_columns, current_value, expected",
+ [
+ ([[1, 2]], 3, (1, 3)),
+ ([[1, 2]], [3, 4], (1, 4)),
+ ([[1.1, 2.2]], 3.3, (1.1, 3.3)),
+ ([[1.1, 2.2]], [3.3, 4.4], (1.1, 4.4)),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ ]
+ ],
+ datetime(2024, 1, 3),
+ (
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 3),
+ ),
+ ),
+ (
+ [
+ [
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 2),
+ ]
+ ],
+ [
+ datetime(2024, 1, 3),
+ datetime(2024, 1, 4),
+ ],
+ (
+ datetime(2024, 1, 1),
+ datetime(2024, 1, 4),
+ ),
+ ),
+ ([[1], []], 2, (1, 2)),
+ ([[1], []], [2, 3], (1, 3)),
+ ([[1], [2]], 3, (1, 3)),
+ ([[1], [2]], [3, 4], (1, 4)),
+ ],
+ )
+ def test_get_min_max_with_current_value(self, data_columns, current_value, expected):
+ targeted_data = pd.DataFrame({f"target_{i}": pd.Series(data) for i, data in enumerate(data_columns)})
+ result = Filter._get_min_max(targeted_data, current_value)
+ assert result == expected
+
+
@pytest.mark.usefixtures("managers_one_page_two_graphs")
class TestFilterInstantiation:
"""Tests model instantiation and the validators run at that time."""
@@ -244,6 +432,73 @@ def test_check_target_present_invalid(self):
Filter(column="foo", targets=["invalid_target"])
+@pytest.mark.usefixtures("managers_column_only_exists_in_some")
+class TestFilterCall:
+ """Test Filter.__call__() method with target_to_data_frame and current_value inputs."""
+
+ def test_filter_call_categorical_valid(self, target_to_data_frame):
+ filter = vm.Filter(
+ column="column_categorical",
+ targets=["column_categorical_exists_1", "column_categorical_exists_2"],
+ selector=vm.Dropdown(id="test_selector_id"),
+ )
+ filter.pre_build()
+
+ selector_build = filter(target_to_data_frame=target_to_data_frame, current_value=["a", "b"])["test_selector_id"]
+ assert selector_build.options == ["ALL", "a", "b", "c"]
+
+ def test_filter_call_numerical_valid(self, target_to_data_frame):
+ filter = vm.Filter(
+ column="column_numerical",
+ targets=["column_numerical_exists_1", "column_numerical_exists_2"],
+ selector=vm.RangeSlider(id="test_selector_id"),
+ )
+ filter.pre_build()
+
+ selector_build = filter(target_to_data_frame=target_to_data_frame, current_value=[1, 2])["test_selector_id"]
+ assert selector_build.min == 1
+ assert selector_build.max == 3
+
+ def test_filter_call_column_is_changed(self, target_to_data_frame):
+ filter = vm.Filter(
+ column="column_categorical", targets=["column_categorical_exists_1", "column_categorical_exists_2"]
+ )
+ filter.pre_build()
+
+ filter._column_type = "numerical"
+
+ with pytest.raises(
+ ValueError,
+ match="column_categorical has changed type from numerical to categorical. "
+ "A filtered column cannot change type while the dashboard is running.",
+ ):
+ filter(target_to_data_frame=target_to_data_frame, current_value=["a", "b"])
+
+ def test_filter_call_selected_column_not_found_in_target(self):
+ filter = vm.Filter(column="column_categorical", targets=["column_categorical_exists_1"])
+ filter.pre_build()
+
+ with pytest.raises(
+ ValueError,
+ match="Selected column column_categorical not found in dataframe for column_categorical_exists_1.",
+ ):
+ filter(target_to_data_frame={"column_categorical_exists_1": pd.DataFrame()}, current_value=["a", "b"])
+
+ def test_filter_call_targeted_data_empty(self):
+ filter = vm.Filter(column="column_categorical", targets=["column_categorical_exists_1"])
+ filter.pre_build()
+
+ with pytest.raises(
+ ValueError,
+ match="Selected column column_categorical does not contain anything in any dataframe "
+ "for column_categorical_exists_1.",
+ ):
+ filter(
+ target_to_data_frame={"column_categorical_exists_1": pd.DataFrame({"column_categorical": []})},
+ current_value=["a", "b"],
+ )
+
+
class TestPreBuildMethod:
def test_targets_default_valid(self, managers_column_only_exists_in_some):
# Core of tests is still interface level
@@ -387,6 +642,72 @@ def test_validate_column_type(self, targets, managers_column_different_type):
):
filter.pre_build()
+ @pytest.mark.usefixtures("managers_one_page_two_graphs")
+ def test_filter_is_not_dynamic(self):
+ filter = vm.Filter(column="continent")
+ model_manager["test_page"].controls = [filter]
+ filter.pre_build()
+ # Filter is not dynamic because it does not target a figure that uses dynamic data
+ assert not filter._dynamic
+ assert not filter.selector._dynamic
+
+ @pytest.mark.usefixtures("managers_one_page_two_graphs_with_dynamic_data")
+ @pytest.mark.parametrize(
+ "test_column, test_selector",
+ [
+ ("continent", vm.Checklist()),
+ ("continent", vm.Dropdown()),
+ ("continent", vm.Dropdown(multi=False)),
+ ("continent", vm.RadioItems()),
+ ("pop", vm.Slider()),
+ ("pop", vm.RangeSlider()),
+ ],
+ )
+ def test_filter_is_dynamic_with_dynamic_selectors(
+ self, test_column, test_selector, gapminder_dynamic_first_n_last_n_function
+ ):
+ data_manager["gapminder_dynamic_first_n_last_n"] = gapminder_dynamic_first_n_last_n_function
+ filter = vm.Filter(column=test_column, selector=test_selector)
+ model_manager["test_page"].controls = [filter]
+ filter.pre_build()
+ # Filter is dynamic because it targets a figure that uses dynamic data
+ assert filter._dynamic
+ assert filter.selector._dynamic
+
+ @pytest.mark.usefixtures("managers_one_page_two_graphs_with_dynamic_data")
+ def test_filter_is_not_dynamic_with_non_dynamic_selectors(self, gapminder_dynamic_first_n_last_n_function):
+ data_manager["gapminder_dynamic_first_n_last_n"] = gapminder_dynamic_first_n_last_n_function
+ filter = vm.Filter(column="year", selector=vm.DatePicker())
+ model_manager["test_page"].controls = [filter]
+ filter.pre_build()
+ assert not filter._dynamic
+
+ @pytest.mark.usefixtures("managers_one_page_two_graphs_with_dynamic_data")
+ @pytest.mark.parametrize(
+ "test_column ,test_selector",
+ [
+ ("continent", vm.Checklist(options=["Africa", "Europe"])),
+ ("continent", vm.Dropdown(options=["Africa", "Europe"])),
+ ("continent", vm.Dropdown(multi=False, options=["Africa", "Europe"])),
+ ("continent", vm.RadioItems(options=["Africa", "Europe"])),
+ ("pop", vm.Slider(min=2002)),
+ ("pop", vm.Slider(max=2007)),
+ ("pop", vm.Slider(min=2002, max=2007)),
+ ("pop", vm.RangeSlider(min=2002)),
+ ("pop", vm.RangeSlider(max=2007)),
+ ("pop", vm.RangeSlider(min=2002, max=2007)),
+ ],
+ )
+ def test_filter_is_not_dynamic_with_options_min_max_specified(
+ self, test_column, test_selector, gapminder_dynamic_first_n_last_n_function
+ ):
+ data_manager["gapminder_dynamic_first_n_last_n"] = gapminder_dynamic_first_n_last_n_function
+ filter = vm.Filter(column=test_column, selector=test_selector)
+ model_manager["test_page"].controls = [filter]
+ filter.pre_build()
+ assert not filter._dynamic
+ assert not filter.selector._dynamic
+
@pytest.mark.parametrize("selector", [vm.Slider, vm.RangeSlider])
def test_numerical_min_max_default(self, selector, gapminder, managers_one_page_two_graphs):
filter = vm.Filter(column="lifeExp", selector=selector())
@@ -500,18 +821,19 @@ def build(self):
assert default_action.actions[0].id == f"filter_action_{filter.id}"
-@pytest.mark.usefixtures("managers_one_page_two_graphs")
class TestFilterBuild:
"""Tests filter build method."""
+ @pytest.mark.usefixtures("managers_one_page_two_graphs")
@pytest.mark.parametrize(
- "test_column,test_selector",
+ "test_column ,test_selector",
[
("continent", vm.Checklist()),
("continent", vm.Dropdown()),
+ ("continent", vm.Dropdown(multi=False)),
("continent", vm.RadioItems()),
- ("pop", vm.RangeSlider()),
("pop", vm.Slider()),
+ ("pop", vm.RangeSlider()),
("year", vm.DatePicker()),
("year", vm.DatePicker(range=False)),
],
@@ -519,7 +841,52 @@ class TestFilterBuild:
def test_filter_build(self, test_column, test_selector):
filter = vm.Filter(column=test_column, selector=test_selector)
model_manager["test_page"].controls = [filter]
+
+ filter.pre_build()
+ result = filter.build()
+ expected = test_selector.build()
+
+ assert_component_equal(result, expected)
+
+ @pytest.mark.usefixtures("managers_one_page_two_graphs_with_dynamic_data")
+ @pytest.mark.parametrize(
+ "test_column, test_selector",
+ [
+ ("continent", vm.Checklist()),
+ ("continent", vm.Dropdown()),
+ ("continent", vm.Dropdown(multi=False)),
+ ("continent", vm.RadioItems()),
+ ("pop", vm.Slider()),
+ ("pop", vm.RangeSlider()),
+ ],
+ )
+ def test_dynamic_filter_build(self, test_column, test_selector, gapminder_dynamic_first_n_last_n_function):
+ # Adding dynamic data_frame to data_manager
+ data_manager["gapminder_dynamic_first_n_last_n"] = gapminder_dynamic_first_n_last_n_function
+ filter = vm.Filter(id="filter_id", column=test_column, selector=test_selector)
+ model_manager["test_page"].controls = [filter]
filter.pre_build()
+
+ result = filter.build()
+ expected = dcc.Loading(
+ id="filter_id",
+ children=test_selector.build(),
+ color="grey",
+ overlay_style={"visibility": "visible"},
+ )
+
+ assert_component_equal(result, expected, keys_to_strip={"className"})
+
+ @pytest.mark.usefixtures("managers_one_page_two_graphs_with_dynamic_data")
+ def test_dynamic_filter_build_with_non_dynamic_selectors(self, gapminder_dynamic_first_n_last_n_function):
+ # Adding dynamic data_frame to data_manager
+ data_manager["gapminder_dynamic_first_n_last_n"] = gapminder_dynamic_first_n_last_n_function
+
+ test_selector = vm.DatePicker()
+ filter = vm.Filter(column="year", selector=test_selector)
+ model_manager["test_page"].controls = [filter]
+ filter.pre_build()
+
result = filter.build()
expected = test_selector.build()
diff --git a/vizro-core/tests/unit/vizro/models/test_dashboard.py b/vizro-core/tests/unit/vizro/models/test_dashboard.py
index e70ed4933..7d9ca5f08 100644
--- a/vizro-core/tests/unit/vizro/models/test_dashboard.py
+++ b/vizro-core/tests/unit/vizro/models/test_dashboard.py
@@ -2,7 +2,6 @@
import dash
import dash_bootstrap_components as dbc
-import dash_mantine_components as dmc
import plotly.io as pio
import pytest
from asserts import assert_component_equal
@@ -58,7 +57,7 @@ def test_field_invalid_pages_empty_list(self):
vm.Dashboard(pages=[])
def test_field_invalid_pages_input_type(self):
- with pytest.raises(ValidationError, match="4 validation errors for Dashboard"):
+ with pytest.raises(ValidationError, match="5 validation errors for Dashboard"):
vm.Dashboard(pages=[vm.Button()])
def test_field_invalid_theme_input_type(self, page_1):
@@ -244,36 +243,20 @@ def test_make_page_404_layout(self, page_1, vizro_app):
# vizro_app fixture is needed to avoid mocking out get_relative_path.
expected = html.Div(
[
- html.Div(
- children=dmc.Switch(
- id="theme_selector",
- checked=False,
- persistence=True,
- persistence_type="session",
- className="toggle-switch",
- ),
- id="settings",
+ dbc.Switch(
+ id="theme-selector",
+ value=False,
+ persistence=True,
+ persistence_type="session",
),
html.Img(),
- html.Div(
- [
- html.Div(
- [
- html.H3("This page could not be found.", className="heading-3-600"),
- html.P("Make sure the URL you entered is correct."),
- ],
- className="error-text-container",
- ),
- dbc.Button("Take me home", href="/"),
- ],
- className="error-content-container",
- ),
+ html.H3("This page could not be found."),
+ html.P("Make sure the URL you entered is correct."),
+ dbc.Button(children="Take me home", href="/", className="mt-4"),
],
- className="page-error-container",
+ className="d-flex flex-column align-items-center justify-content-center min-vh-100",
)
-
- # Strip out src since it's too long to be worth comparing and just comes directly
- # from reading a file.
+ # Strip out src since it's too long to be worth comparing and just comes directly from reading a file.
assert_component_equal(vm.Dashboard(pages=[page_1])._make_page_404_layout(), expected, keys_to_strip={"src"})
diff --git a/vizro-core/tests/unit/vizro/tables/test_dash_table.py b/vizro-core/tests/unit/vizro/tables/test_dash_table.py
index 490610618..d903050cb 100644
--- a/vizro-core/tests/unit/vizro/tables/test_dash_table.py
+++ b/vizro-core/tests/unit/vizro/tables/test_dash_table.py
@@ -36,17 +36,17 @@ def test_dash_data_table(self):
data=data_in_table,
style_as_list_view=True,
style_cell={"position": "static"},
- style_data={"border_bottom": "1px solid var(--border-subtle-alpha-01)", "height": "40px"},
+ style_data={"border_bottom": "1px solid var(--border-subtleAlpha01)", "height": "40px"},
style_header={
- "border_bottom": "1px solid var(--state-overlays-selected-hover)",
- "border_top": "1px solid var(--main-container-bg-color)",
+ "border_bottom": "1px solid var(--stateOverlays-selectedHover)",
+ "border_top": "1px solid var(--right-side-bg)",
"height": "32px",
},
style_data_conditional=[
{
"if": {"state": "active"},
- "backgroundColor": "var(--state-overlays-selected)",
- "border": "1px solid var(--state-overlays-selected)",
+ "backgroundColor": "var(--stateOverlays-selected)",
+ "border": "1px solid var(--stateOverlays-selected)",
}
],
),