Photo © 2022 by bord
@@ -18,7 +18,7 @@ VPE provides a component that you can add to your existing gate. By doing that,
## Setup
-
+
In order to add the lifting gate feature to a gate, select the game object of the gate and click on *Add Component* in the inspector. Select it by searching or navigating to *Visual Pinball -> Mechs -> Gate Lifter*.
@@ -35,4 +35,4 @@ How fast the gate rotates from and into the decativated position. Higher is fast
Adding the gate lifter component adds a coil input to the gate, i.e. you can map it to any of the gamelogic engine's coil outputs through the [Coil Manager](xref:coil_manager).
> [!NOTE]
-> If you're working on an EM game or an original game with [Visual Scripting](xref:uvs_index), don't forget to add the new coil to the [coil definitions](xref:uvs_setup#coils).
\ No newline at end of file
+> If you're working on an EM game or an original game with [Visual Scripting](xref:uvs_index), don't forget to add the new coil to the [coil definitions](xref:uvs_setup#coils).
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
index 9dffbf031..ac9c364e2 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
@@ -6,13 +6,13 @@ description: VPE can group and address multiple lights at once.
# Light Groups
-Sometimes, a game addresses multiple physical lights as one logical lamp, i.e. all lights are always toggled or faded at the same time. Typical use cases are [GI strips](https://docs.missionpinball.org/en/latest/mechs/lights/gis.html). Instead of creating a link in the [Lamp Manager](xref:lamp_manager) for each light separately, VPE ships with a component called *Lamp Group*.
+Sometimes, a game addresses multiple physical lights as one logical lamp, i.e. all lights are always toggled or faded at the same time. Typical use cases are [GI strips](https://missionpinball.org/mechs/lights/gis/). Instead of creating a link in the [Lamp Manager](xref:lamp_manager) for each light separately, VPE ships with a component called *Lamp Group*.
A light group is a component you can add to any GameObject. It's recommended to make it parent of the light objects it contains, but you can also keep it outside of the lights hierarchy, since it explicitly references the lights it contains.
## Setup
-
+
To create a new light group, select the GameObject you want to add your light group to, and in the inspector click on *Add Component* and choose *Visual Pinball -> Game Item -> Light Group*.
@@ -34,4 +34,4 @@ Simply clears the list.
When working with lights, the GameObject with the actual light source is nested within the main object. This can make adjusting light settings for multiple lights tedious, since you have to drill into each parent in order to select the source.
-This button selects all the source GameObjects for the lights in the light group.
\ No newline at end of file
+This button selects all the source GameObjects for the lights in the light group.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md
index eda42327f..1a4451d2b 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md
@@ -12,7 +12,7 @@ Sometimes during gameplay, you might need to rotate objects in order to recreate
## Setup
-
+
In order to create a rotator, add the **Rotator** component to a game object by clicking *Add Component* in the inspector, then choosing *Visual Pinball -> Game Item -> Rotator*. You can use any game object, although we recommend adding it to the target that you want to rotate.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-motors.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-motors.md
index 27d920d36..b88d467e4 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-motors.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-motors.md
@@ -37,7 +37,7 @@ To setup a score motor, select any game object, click on *Add Component* in the
Next, configure the score motor. The inspector shows the following options:
-
+
- **Steps** defines how many steps the score motor pulses for one turn.
- **Duration** defines the length of time it takes the score motor to completely cycle.
@@ -47,7 +47,7 @@ Next, configure the score motor. The inspector shows the following options:
> [!NOTE]
> The minimum amount of `Steps` for a score motor is `5`. `Increase by 5` will not be shown under `Reel timing by increase` if `Steps` is set to 5, as all actions would be `Increase`.
-
+
By default, the score motor is configured to:
@@ -94,4 +94,4 @@ In order to hook into those switches, you'll have to create them in the GLE insp
-Then, in your graphs, add your logic behind the corresponding [On Switch Changed](xref:uvs_node_reference#on-switch-changed) node(s).
\ No newline at end of file
+Then, in your graphs, add your logic behind the corresponding [On Switch Changed](xref:uvs_node_reference#on-switch-changed) node(s).
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-reels.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-reels.md
index a265fe57b..9eadb016d 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-reels.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/score-reels.md
@@ -6,7 +6,7 @@ description: How to use EM-style reels to display the score.
# Score Reel Displays
-
+
In electro-mechanical games, score reels are very common for displaying the player score. Typically, four to six units are mounted behind the backglass. Each reel is driven by a coil that advances the reel by one position when pulsed. The coils are driven by the playfield elements in the game, often indirectly through a score motor for multi-point scoring.
@@ -39,7 +39,7 @@ In your scene, drop in your reel model and add the *Score Reel* component (not t
#### Score Reel
-
+
The *Score Reel* component is quick to set up. There is only one option, which is the *rotation direction*. What the score reel component gets from the display component is "turn to position X", where X is between 0 and 9, and the component's job is to animate the reel to that position.
@@ -47,7 +47,7 @@ Internally, it also takes in the rotation speed, and how long it rests at the fi
#### Score Reel Display
-
+
This is the component on the parent game object that receives score numbers from the game and tells the individual reels to which position they need to turn to.
@@ -62,7 +62,7 @@ This is the component on the parent game object that receives score numbers from
### Gamelogic Engine
-
+
Score reels are primarily used in EMs, so they are typically driven by [Visual Scripting](xref:uvs_index). As with every display, the first step is to define the display in the GLE component.
@@ -74,4 +74,4 @@ Next, add *Numeric* under *Supported Formats*.
In Visual Scripting, use the [Update Display](xref:uvs_node_reference#update-display) node to set a new score. It's up to you whether to use a separate [event](xref:uvs_setup#events) or to subscribe to a [player variable](xref:uvs_variables) directly.
-If you're using a score motor, read how to set it up correctly [here](xref:score-motors#usage).
\ No newline at end of file
+If you're using a score motor, read how to set it up correctly [here](xref:score-motors#usage).
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md
index 9e12add05..c6785146c 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md
@@ -15,7 +15,7 @@ VPE does provide a slingshot component that implements the rubber animation duri
# Setup
-
+
### Slingshot Wall
@@ -34,7 +34,7 @@ To set the start and end positions of the control points, we reference two rubbe
On physical machines, the rubber is moved by an arm attached to the coil. VPE can simulate the movement of that arm by rotating a primitive across the X-axis. In the *Coil Arm* field, a reference to the primive can be set, and the total angle of rotation under *Arm Angle*.
-
+
### Animation
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
index 77397bffe..7c2e42eb2 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
@@ -15,7 +15,7 @@ Sometimes it's easier to teleport the ball from one place to another instead of
## Setup
-
+
In order to create a new teleporter, select the GameObject you want to add it to, click on *Add Component* and select *Visual Pinball -> Game Item -> Teleporter*. You can choose any GameObject, although we recommend putting it on same GameObject as the source kicker.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/troughs.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/troughs.md
index c2b285dba..4b91ae7c9 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/troughs.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/troughs.md
@@ -16,7 +16,7 @@ When importing a `.vpx` file that doesn't have any troughs (which is likely, bec
## Linking to the Playfield
-
+
To interact with the game, you must set up an **input switch** to drain the ball into the trough, and an **exit kicker** to release a new ball from the trough. This terminology may seem weird, since the ball *exits* the playfield when draining, but from the trough's perspective, that's where the ball *enters*.
@@ -44,9 +44,9 @@ In this section we'll again link to the excellent MPF documentation explaining e
### Modern Mechanical
-
+
-[Modern troughs with mechanical switches](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-2-modern-trough-with-mechanical-switches) are covered by this type.
+[Modern troughs with mechanical switches](https://missionpinball.org/mechs/troughs/#option-2-modern-trough-with-mechanical-switches) are covered by this type.
The ball drains from the playfield directly into the ball stack, and every ball slot has an associated switch. When a ball gets ejected, the remaining balls move down simultaneously to the next position. During that movement, their switches get first opened and then closed again when they reach the next position. The time of this movement is defined by *Roll Time*.
@@ -54,9 +54,9 @@ The ball drains from the playfield directly into the ball stack, and every ball
### Modern Opto
-
+
-[Modern troughs with optical switches](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-1-modern-trough-with-opto-sensors) work similar similar to their mechanical counterparts. However there are two differences:
+[Modern troughs with optical switches](https://missionpinball.org/mechs/troughs/#option-1-modern-trough-with-opto-sensors) work similar similar to their mechanical counterparts. However there are two differences:
1. Opto switches have the inverse value of mechanical switches. That means per default, an opto switch is *closed*, and when a ball rolls through, it opens. It's kind of logical, because the ball *blocks* the beam of light thus *opening* the circuit, while a mechanical switch gets *closed* by the ball's weight.
2. Timings are different. When a ball approaches an opto switch, the switch gets triggered as soon as the ball's *front* hits the beam, while a mechanical switch gets triggered when the ball's *center* is over it. This results in very short closing times when the ball stack moves to the next position after a ball eject.
@@ -70,9 +70,9 @@ We call this closing time the *transition time* - it's the time during stack tra
### Two coils and multiple switches
-
+
-[Troughs of this type](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-3-older-style-with-two-coils-and-switches-for-each-ball) can be found in older machines from the 80s and early 90s. They consist of two parts:
+[Troughs of this type](https://missionpinball.org/mechs/troughs/#option-3-older-style-with-two-coils-and-switches-for-each-ball) can be found in older machines from the 80s and early 90s. They consist of two parts:
1. A drain, the ball rolls into when leaving the playfield
2. A ball stack, where the out of play balls are held.
@@ -83,9 +83,9 @@ In terms of switches, they still include a switch per ball in the stack, but als
### Two coils and one switch
-
+
-A trough can also have [only one switch](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-4-older-style-with-two-coils-and-only-one-ball-switch) in the ball stack.
+A trough can also have [only one switch](https://missionpinball.org/mechs/troughs/#option-4-older-style-with-two-coils-and-only-one-ball-switch) in the ball stack.
Instead of a *Switch Count* like the previous types, you select a *Switch Position*, which is the position in the ball stack at which the ball farthest away from the eject coil sits.
@@ -93,9 +93,9 @@ Instead of a *Switch Count* like the previous types, you select a *Switch Positi
### Classic single ball
-
+
-A single ball trough may work [with](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-5-classic-single-ball-single-coil) or [without](https://docs.missionpinball.org/en/latest/mechs/troughs/#option-6-classic-single-ball-single-coil-no-shooter-lane) a shooter lane. The principle is simple: After draining, the ball is kept on the drain coil, which ejects the ball either directly into the plunger lane or back onto the playfield.
+A single ball trough may work [with](https://missionpinball.org/mechs/troughs/#option-5-classic-single-ball-single-coil) or [without](https://missionpinball.org/mechs/troughs/#option-6-classic-single-ball-single-coil-no-shooter-lane) a shooter lane. The principle is simple: After draining, the ball is kept on the drain coil, which ejects the ball either directly into the plunger lane or back onto the playfield.
*The animation shows single ball trough that ejects a ball and drains it a few seconds later.*
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/setup/installing-vpe.md b/VisualPinball.Unity/Documentation~/creators-guide/setup/installing-vpe.md
index 6087321fa..23a22fb7a 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/setup/installing-vpe.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/setup/installing-vpe.md
@@ -13,16 +13,11 @@ In order to start creating or modifying tables with VPE, the first thing you'll
Unity uses an application called *Unity Hub* to update itself, create new projects and provide quick access to them. The install process is straight-forward and documented [here](https://docs.unity3d.com/Manual/GettingStartedInstallingHub.html) if you run into troubles.
-**2021.3.0** is the latest version supported by VPE so click on *Skip Installation* in the first dialog to avoid installing the newest version of the Editor. After accepting the license agreement you will have access to Unity Hub.
-
-> [!NOTE]
-> To install the supported version of the editor you can either
-> * Paste this direct link into your browser: unityhub://2021.3.0f1/6eacc8284459
-> * Find the correct version from the [Unity release archive](https://unity3d.com/get-unity/download/archive)
+**2022.3** is the recommended Unity version at the moment. Once 2023 is officially out, we'll be updating the dependencies and the documentation.
You can leave all the other options unchecked during install.
-Once Unity is downloaded and installed, you're ready to create a new VPE project. Click on *New Project*, be sure to have selected the 2021.3.0f1 version at the top, and you'll see the following choices:
+Once Unity is downloaded and installed, you're ready to create a new VPE project. Click on *New Project*, be sure to have selected the 2022.3 version at the top, and you'll see the following choices:

diff --git a/VisualPinball.Unity/Documentation~/creators-guide/setup/running-vpe.md b/VisualPinball.Unity/Documentation~/creators-guide/setup/running-vpe.md
index b98909be1..35b3235a1 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/setup/running-vpe.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/setup/running-vpe.md
@@ -19,7 +19,7 @@ Now that we have the camera of the scene view somewhat aligned, we still can't s

-
+
These orange artifacts are what Unity calls [Gizmo Icons](https://docs.unity3d.com/Manual/GizmosMenu.html). They are enabled by default, and since VPE uses icons for its playfield elements, they are all over the place. Unity's default gizmo size is adapted for rather large scenes and we're dealing with a pinball table, let's make them smaller by clicking on the gizmo icon in the *Scene* view, and pull the size *3D Icons* slider down until you're happy. You can additionally hide the VPE icons by clicking on *Visual Pinball -> Editor -> Disable Gizmo Icons*.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
index 9fa539b1e..b6d1f7c04 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
+++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
@@ -37,50 +37,50 @@
href: tutorials/index.md
items:
- name: Create a Playfield
- href: xref:tutorial_playfield
+ uid: tutorial_playfield
items:
- name: Albedo Texture and Masks
- href: xref:tutorial_playfield_1
+ uid: tutorial_playfield_1
- name: Playfield Mesh
- href: xref:tutorial_playfield_2
+ uid: tutorial_playfield_2
- name: Texturing
- href: xref:tutorial_playfield_3
+ uid: tutorial_playfield_3
- name: Texturing (details)
- href: xref:tutorial_playfield_3b
+ uid: tutorial_playfield_3b
- name: Import Into Unity
- href: xref:tutorial_playfield_4
+ uid: tutorial_playfield_4
- name: Create Realistic Looking Plastics
- href: xref:tutorial_plastics
+ uid: tutorial_plastics
items:
- name: Prepare Artwork
- href: xref:tutorial_plastics_1
+ uid: tutorial_plastics_1
- name: Create Mesh
- href: xref:tutorial_plastics_2
+ uid: tutorial_plastics_2
- name: UV-Map Mesh
- href: xref:tutorial_plastics_3
+ uid: tutorial_plastics_3
- name: Import Into Unity
- href: xref:tutorial_plastics_4
+ uid: tutorial_plastics_4
- name: Create a Backglass
- href: xref:tutorial_backglass
+ uid: tutorial_backglass
items:
- name: Prepare Artwork
- href: xref:tutorial_backglass_1
+ uid: tutorial_backglass_1
- name: Create Mesh
- href: xref:tutorial_backglass_2
+ uid: tutorial_backglass_2
- name: Import into Unity
- href: xref:tutorial_backglass_3
+ uid: tutorial_backglass_3
- name: Make a 3D Scan Game-Ready
- href: xref:tutorial_3d_scan
+ uid: tutorial_3d_scan
items:
- name: Clean Up the Mesh
- href: xref:tutorial_3d_scan_1
+ uid: tutorial_3d_scan_1
- name: Retopologize
- href: xref:tutorial_3d_scan_2
+ uid: tutorial_3d_scan_2
- name: Bake Texture Maps
- href: xref:tutorial_3d_scan_3
+ uid: tutorial_3d_scan_3
- name: Manual
href: manual/manual.md
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/index.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/index.md
index c88b98532..9d80566cb 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/index.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/index.md
@@ -9,3 +9,4 @@ description: Visual Pinball for Unity - Tutorials
- [Create a Playfield](xref:tutorial_playfield)
- [Create Realistic Looking Plastics](xref:tutorial_plastics)
- [Create a Backglass](xref:tutorial_backglass)
+- [Make a 3D Scan Game-Ready](xref:tutorial_3d_scan)
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-backglass/1-prepare-artwork.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-backglass/1-prepare-artwork.md
index e6f7e4445..6a65a2d5e 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-backglass/1-prepare-artwork.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-backglass/1-prepare-artwork.md
@@ -16,7 +16,7 @@ Once you have your artwork secured save this as a PNG file. We'll name it `Backg
## Create the Thickness Mask
-
+
To block the passage of light through the backglass we need to make a thickness map layer. This layer consists of pure white for the areas that are opaque and pure black for the areas that are transparent. If you have physical access to the backglass then you can scan the backside to get this mask. Otherwise, you'll have to trace what's visible on the front, and try to reconstruct elements that aren't.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md
index 5cc59bb12..6dca3596b 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md
@@ -63,7 +63,7 @@ Note the *Links* toolbox that shows the individual plastic files. Also note the
## Step 3: Export Texture and Outlines
-
+
We'll first export the texture. In Illustrator, click on *File -> Export -> Export As...*, and make sure *Use Artboards* is checked. As type, select *PNG*. Then, enter `Plastics.png` as file name and click on *Export*, which will result in the dialog seen in the screenshot.
@@ -87,7 +87,7 @@ Your document should now look like this:
Don't worry about the color, it just needs to be filled in any color. I'm using magenta because it gives a good contrast to the rest of the artwork.
-
+
Click on *File -> Save a Copy...*, enter `Plastics.svg` as file name, save as type *SVG* and make sure *Use Artboards* is unchecked this time. Click on *Save*. In the options panel, click on *More Options* and make sure all the options are disabled as shown in the screenshot.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md
index 04853325d..cab044901 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md
@@ -11,7 +11,7 @@ description: How to UV-map the texture onto your mesh in Blender
We need three material slots, for the top and bottom faces, as well as for the edges. We'll split the vertices by firstly assigning everything to an "edge" slot, and then re-assigning the top and bottom faces to their own slots.
-
+
In object mode, open *Materials* properties and remove the current material slot (hit `-`). Add three new slots (press 3× `+`), and for each slot, create a new material by hitting the *New* button when the slot is selected. Name them "top", "bottom" and "edge" and set their base color to red, green, and blue respectively. Your slots should now look like in the screenshot.
@@ -21,7 +21,7 @@ Then, press `7` on the numpad to switch to top view, zoom in a bit so you can cl

-
+
Click on *Select -> Select Similar -> Coplanar*, which should result in all top faces of all plastics being selected (but *not* the bottoms ones). However, you might get the bottom faces selected too, because there's a threshold that might be too large. You can check it by rotating the camera and verify that the bottom faces are not selected. If they are, expand the parameters and set the threshold to a small enough value. Then, select the "top" material slot and hit *Assign*. The top surfaces should turn red.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md
index 6f6d1ecb0..45f2121ee 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md
@@ -23,7 +23,7 @@ We recommend unpacking the prefab. Unpacking will still reference the meshes of
First, let's configure how the texture is imported. In the *Project* window, navigate to `Assets/
/Textures` where you saved `Plastics.png`, and select it. In the *Inspector* window, check the option *Alpha Is Transparent*. Depending on how large you've exported it, you might need to update *Max Size* as well, in our case we'll use 4096 × 4096. When you're done, hit *Apply* at the bottom.
-
+
Next, we'll create a material of our bottom surface. In the *Project* window, navigate to `Packages/Visual Pinball Engine (HDRP)/Assets/Art/Materials/Default/Plastic`, select `Plastics Decal`, hit `Ctrl`+`C`. Navigate to your project's `Assets//Materials` folder, and press `Ctrl`+`V`.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/1-textures.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/1-textures.md
index a133342fd..cf0ef45d7 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/1-textures.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/1-textures.md
@@ -10,7 +10,7 @@ In this first step, we'll go through how to create the various textures that we
## Texture Layout
-
+
The geometry of the playfield has three different areas:
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/4-import-into-unity.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/4-import-into-unity.md
index a383b0b15..0b47c20e5 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/4-import-into-unity.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-playfield/4-import-into-unity.md
@@ -15,7 +15,7 @@ First, let's bring our files into the Unity project. There are four files that g
While the import options for the FBX file are fine, we need to adjust them for the textures.
-
+
Select the base texture and change the following options in the *Inspector*:
diff --git a/VisualPinball.Unity/Documentation~/docfx.json b/VisualPinball.Unity/Documentation~/docfx.json
index c6e7308c0..c5d29bcf6 100644
--- a/VisualPinball.Unity/Documentation~/docfx.json
+++ b/VisualPinball.Unity/Documentation~/docfx.json
@@ -1,103 +1,63 @@
{
- "metadata": [
- {
- "src": [
- {
- "files": [
- "VisualPinball.Unity/**.csproj",
- "VisualPinball.Unity.Patcher/**.csproj"
- ],
- "src": "../"
- }
- ],
- "dest": "api",
- "disableGitFeatures": false,
- "disableDefaultFilter": false,
- "filter": "filterConfig.yml"
- }
- ],
- "build": {
- "content": [
- {
- "files": [
- "api/**.yml",
- "api/index.md"
- ]
- },
- {
- "files": [
- "creators-guide/**/toc.yml",
- "creators-guide/**.md",
- "plugins/**/toc.yml",
- "plugins/**.md",
- "toc.yml",
- "*.md"
- ]
- },
- {
- "files": "CHANGELOG.md",
- "src": "../.."
- }
- ],
- "resource": [
- {
- "files": [
- "**/*.png",
- "**/*.gif",
- "**/*.jpg",
- "**/*.svg",
- "**/*.ico",
- "**/*.webp",
- "**/*.webmanifest",
- "../VisualPinball.Unity.Editor/Resources/Icons/*.png",
- "CNAME"
- ]
- },
- {
- "files": "static/**/*.woff*",
- "dest": "/fonts"
- },
- {
- "files": "static/*.css",
- "dest": "/styles"
- }
- ],
- "overwrite": [
- {
- "files": [
- "apidoc/**.md"
- ],
- "exclude": [
- "obj/**",
- "_site/**"
- ]
- }
- ],
- "dest": "_site",
- "globalMetadataFiles": [],
- "fileMetadataFiles": [],
- "template": [
- "default",
- "template/vpe",
- "template/lightbox-featherlight"
- ],
- "postProcessors": [ "ExtractSearchIndex" ],
- "globalMetadata": {
- "_appTitle": "VPE Documentation",
- "_appFooter": "Copyright © 2022 VPE Team ",
- "_gitContribute": {
- "branch": "master"
- }
- },
- "sitemap":{
- "baseUrl": "https://docs.visualpinball.org/",
- "priority": 0.5,
- "changefreq": "weekly"
- },
- "markdownEngineName": "markdig",
- "noLangKeyword": false,
- "keepFileLink": false,
- "cleanupCacheHistory": false,
- "disableGitFeatures": false
- }
-}
\ No newline at end of file
+ "build": {
+ "content": [
+ {
+ "files": [
+ "creators-guide/**/toc.yml",
+ "creators-guide/**.md",
+ "plugins/**/toc.yml",
+ "plugins/**.md",
+ "toc.yml",
+ "*.md"
+ ]
+ },
+ {
+ "files": "CHANGELOG.md",
+ "src": "../.."
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "**/*.png",
+ "**/*.gif",
+ "**/*.jpg",
+ "**/*.svg",
+ "**/*.ico",
+ "**/*.webp",
+ "**/*.webmanifest",
+ "../VisualPinball.Unity.Editor/Resources/Icons/*.png",
+ "CNAME"
+ ]
+ }
+ ],
+ "output": "_site",
+ "globalMetadataFiles": [],
+ "fileMetadataFiles": [],
+ "template": [
+ "default",
+ "modern",
+ "template/vpe"
+ ],
+ "postProcessors": [ "ExtractSearchIndex" ],
+ "globalMetadata": {
+ "_appTitle": "VPE Documentation",
+ "_appFooter": "Copyright © 2023 VPE Team ",
+ "_appFaviconPath": "favicon.png",
+ "_gitContribute": {
+ "branch": "master"
+ },
+ "_enableSearch": true
+ },
+ "sitemap":{
+ "baseUrl": "https://docs.visualpinball.org/",
+ "priority": 0.5,
+ "changefreq": "weekly"
+ },
+ "markdownEngineName": "markdig",
+ "noLangKeyword": false,
+ "keepFileLink": false,
+ "cleanupCacheHistory": false,
+ "disableGitFeatures": false
+ }
+}
diff --git a/VisualPinball.Unity/Documentation~/favicon-16x16.png b/VisualPinball.Unity/Documentation~/favicon-16x16.png
deleted file mode 100644
index 4b05796cc..000000000
Binary files a/VisualPinball.Unity/Documentation~/favicon-16x16.png and /dev/null differ
diff --git a/VisualPinball.Unity/Documentation~/favicon-32x32.png b/VisualPinball.Unity/Documentation~/favicon-32x32.png
deleted file mode 100644
index 6d35bc185..000000000
Binary files a/VisualPinball.Unity/Documentation~/favicon-32x32.png and /dev/null differ
diff --git a/VisualPinball.Unity/Documentation~/favicon.ico b/VisualPinball.Unity/Documentation~/favicon.ico
index 5bea928f4..8e856771e 100644
Binary files a/VisualPinball.Unity/Documentation~/favicon.ico and b/VisualPinball.Unity/Documentation~/favicon.ico differ
diff --git a/VisualPinball.Unity/Documentation~/favicon.png b/VisualPinball.Unity/Documentation~/favicon.png
index 4d964c565..fcdc0111e 100644
Binary files a/VisualPinball.Unity/Documentation~/favicon.png and b/VisualPinball.Unity/Documentation~/favicon.png differ
diff --git a/VisualPinball.Unity/Documentation~/filterConfig.yml b/VisualPinball.Unity/Documentation~/filterConfig.yml
deleted file mode 100644
index 61502fb71..000000000
--- a/VisualPinball.Unity/Documentation~/filterConfig.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-apiRules:
- - include:
- hasAttribute:
- uid: VisualPinball.Unity.ApiAttribute
- - exclude:
- uidRegex: '^VisualPinball\.Unity\..*'
- type: Type
- - exclude:
- uidRegex: ^System\.Object
- type: Type
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/index.md b/VisualPinball.Unity/Documentation~/index.md
index 38d0495ac..51c3aad98 100644
--- a/VisualPinball.Unity/Documentation~/index.md
+++ b/VisualPinball.Unity/Documentation~/index.md
@@ -1,15 +1,496 @@
---
title: Welcome
description: Visual Pinball for Unity - Documentation, Guides and Tutorials.
+layout: landing
+is_full: true
---
Welcome to the documentation of the
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[Start here with the creator's guide](xref:vpe-overview).
*Be aware we're at the very beginning of writing documentation. You'll see weird content.*
-
\ No newline at end of file
+
diff --git a/VisualPinball.Unity/Documentation~/plugins/index.md b/VisualPinball.Unity/Documentation~/plugins/index.md
index 996f2ce04..7c55af80f 100644
--- a/VisualPinball.Unity/Documentation~/plugins/index.md
+++ b/VisualPinball.Unity/Documentation~/plugins/index.md
@@ -14,7 +14,7 @@ VPE has a plug-in system that allows other software to integrate with it. Plugin
## [Visual Scripting](xref:uvs_index)
-For original games or EM machines, we recommend using our visual scripting package which extends [Unity's visual scripting](https://unity.com/products/unity-visual-scripting).
+For original games or EM machines, we recommend using our visual scripting package which extends [Unity's Visual Scripting](https://unity.com/products/unity-visual-scripting).
## [Mission Pinball Framework](xref:mpf_index)
diff --git a/VisualPinball.Unity/Documentation~/plugins/pinmame/mechs.md b/VisualPinball.Unity/Documentation~/plugins/pinmame/mechs.md
index 5a3462b8c..970f82b46 100644
--- a/VisualPinball.Unity/Documentation~/plugins/pinmame/mechs.md
+++ b/VisualPinball.Unity/Documentation~/plugins/pinmame/mechs.md
@@ -34,7 +34,7 @@ This page is about approach #2 and describes how you can configure and use PinMA
## Setup
-
+
PinMAME can simulate up to five custom mechs. You create one by adding the *PinMAME Mech* component onto a game object.
diff --git a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/complementary-usage.md b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/complementary-usage.md
index 06877aa0f..b79fb45b8 100644
--- a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/complementary-usage.md
+++ b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/complementary-usage.md
@@ -14,7 +14,7 @@ In this case, we'd like to keep PinMAME as the driving GLE, but add a visual scr
## Setup
-
+
In order to give VPE's visual scripting nodes access to your game logic engine, we provide what we call a *Visual Scripting Bridge*. It's a component that you'll need to add to your table's game object, along with your original gamelogic engine. You can do that by selecting the game object, clicking *Add Component* in the inspector, and choosing *Visual Pinball -> Gamelogic Engine -> Visual Scripting Game Logic*.
diff --git a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/setup.md b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/setup.md
index 8cca136d7..42622ce48 100644
--- a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/setup.md
+++ b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/setup.md
@@ -18,7 +18,7 @@ So instead of interacting with playfield items directly, you need to define the
### Displays
-
+
The first configuration you'll see in the inspector is which type of displays your game expects to find on the playfield. You can have multiple displays. For each display, you define the size and which type of formats it must be able to handle. These are the possible types:
@@ -33,19 +33,19 @@ The display components that VPE provides understand multiple formats, e.g., our
### Switches
-
+
In this section you define the switches that appear in the [Switch Manager](xref:switch_manager) when you auto-populate them. It's also the source for all the [switch-related nodes](xref:uvs_node_reference#switches) that VPE provides within your visual scripting graphs.
### Coils
-
+
Here you define your coils. Same concept as for switches. These are the coils you'll see in the [Coil Manager](xref:coil_manager), and they are the source when looking up IDs in visual scripting's [coil nodes](xref:uvs_node_reference#coils).
### Lamps
-
+
Same goes for the lamps. They appear in the [Lamp Manager](xref:lamp_manager) and are used in the [lamp nodes](xref:uvs_node_reference#lamps) that VPE provides.
@@ -53,7 +53,7 @@ It's worth noting that VPE currently doesn't provide any tools for creating ligh
### Events
-
+
Unity provides [Custom Events](https://docs.unity3d.com/Packages/com.unity.visualscripting@1.7/manual/vs-events-reference.html#custom-events) which allow you to globally pass data across graphs. While this is a valid approach, VPE provides its own event nodes called *Pinball Events*, which allow you to declare your events. This has the benefit of being able to simply pick an event from a drop-down when configuring the nodes, as opposed to having to remember or separately document existing event names.
diff --git a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/variables.md b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/variables.md
index c2ee5423e..27a296d5d 100644
--- a/VisualPinball.Unity/Documentation~/plugins/visual-scripting/variables.md
+++ b/VisualPinball.Unity/Documentation~/plugins/visual-scripting/variables.md
@@ -32,7 +32,7 @@ If you're testing gameplay in the editor, the current values of both player and
### Setup
-
+
In the hierarchy, select the GameObject where you added the visual scripting GLE (usually the root node of the table). In there, you'll find two sections, *Player Variables* and *Table Variables*.
diff --git a/VisualPinball.Unity/Documentation~/safari-pinned-tab.svg b/VisualPinball.Unity/Documentation~/safari-pinned-tab.svg
deleted file mode 100644
index 426281cc1..000000000
--- a/VisualPinball.Unity/Documentation~/safari-pinned-tab.svg
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-Created by potrace 1.11, written by Peter Selinger 2001-2013
-
-
-
-
-
diff --git a/VisualPinball.Unity/Documentation~/site.webmanifest b/VisualPinball.Unity/Documentation~/site.webmanifest
index 03860619f..6de1ad0de 100644
--- a/VisualPinball.Unity/Documentation~/site.webmanifest
+++ b/VisualPinball.Unity/Documentation~/site.webmanifest
@@ -1,18 +1,6 @@
{
"name": "Visual Pinball Engine - Documentation",
"short_name": "VPE Documentation",
- "icons": [
- {
- "src": "/android-chrome-192x192.png",
- "sizes": "192x192",
- "type": "image/png"
- },
- {
- "src": "/android-chrome-256x256.png",
- "sizes": "256x256",
- "type": "image/png"
- }
- ],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
diff --git a/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/partials/scripts.tmpl.partial b/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/partials/scripts.tmpl.partial
deleted file mode 100644
index 16b384b48..000000000
--- a/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/partials/scripts.tmpl.partial
+++ /dev/null
@@ -1,7 +0,0 @@
-{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
-
-
-
-
-
-
diff --git a/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/styles/plugin-featherlight.js b/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/styles/plugin-featherlight.js
deleted file mode 100644
index f4283ebe8..000000000
--- a/VisualPinball.Unity/Documentation~/template/lightbox-featherlight/styles/plugin-featherlight.js
+++ /dev/null
@@ -1,15 +0,0 @@
-$(document).ready(function() {
- //find all images, but not the logo, and add the lightbox
- $('img').not('.logo').each(function(){
- var $img = $(this);
- var filename = $img.attr('src')
- //add cursor
- $img.css('cursor','zoom-in');
- $img.css('cursor','-moz-zoom-in');
- $img.css('cursor','-webkit-zoom-in');
-
- //add featherlight
- $img.attr('alt', filename);
- $img.featherlight(filename);
- });
-});
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/inter.css b/VisualPinball.Unity/Documentation~/template/vpe/fonts/inter.css
deleted file mode 100644
index 66c7fb69c..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/fonts/inter.css
+++ /dev/null
@@ -1,200 +0,0 @@
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-Thin.woff2?v=3.15") format("woff2"),
- url("Inter-Thin.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-ThinItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ThinItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLight.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraLight.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLightItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraLightItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-Light.woff2?v=3.15") format("woff2"),
- url("Inter-Light.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-LightItalic.woff2?v=3.15") format("woff2"),
- url("Inter-LightItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 400;
- font-display: swap;
- src: url("Inter-Regular.woff2?v=3.15") format("woff2"),
- url("Inter-Regular.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url("Inter-Italic.woff2?v=3.15") format("woff2"),
- url("Inter-Italic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-Medium.woff2?v=3.15") format("woff2"),
- url("Inter-Medium.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-MediumItalic.woff2?v=3.15") format("woff2"),
- url("Inter-MediumItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBold.woff2?v=3.15") format("woff2"),
- url("Inter-SemiBold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBoldItalic.woff2?v=3.15") format("woff2"),
- url("Inter-SemiBoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url("Inter-Bold.woff2?v=3.15") format("woff2"),
- url("Inter-Bold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url("Inter-BoldItalic.woff2?v=3.15") format("woff2"),
- url("Inter-BoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBold.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraBold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBoldItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraBoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-Black.woff2?v=3.15") format("woff2"),
- url("Inter-Black.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-BlackItalic.woff2?v=3.15") format("woff2"),
- url("Inter-BlackItalic.woff?v=3.15") format("woff");
-}
-
-/* -------------------------------------------------------
-Variable font.
-Usage:
-
- html { font-family: 'Inter', sans-serif; }
- @supports (font-variation-settings: normal) {
- html { font-family: 'Inter var', sans-serif; }
- }
-*/
-@font-face {
- font-family: 'Inter var';
- font-weight: 100 900;
- font-display: swap;
- font-style: normal;
- font-named-instance: 'Regular';
- src: url("Inter-roman.var.woff2?v=3.15") format("woff2");
-}
-@font-face {
- font-family: 'Inter var';
- font-weight: 100 900;
- font-display: swap;
- font-style: italic;
- font-named-instance: 'Italic';
- src: url("Inter-italic.var.woff2?v=3.15") format("woff2");
-}
-
-
-/* --------------------------------------------------------------------------
-[EXPERIMENTAL] Multi-axis, single variable font.
-
-Slant axis is not yet widely supported (as of February 2019) and thus this
-multi-axis single variable font is opt-in rather than the default.
-
-When using this, you will probably need to set font-variation-settings
-explicitly, e.g.
-
- * { font-variation-settings: "slnt" 0deg }
- .italic { font-variation-settings: "slnt" 10deg }
-
-*/
-@font-face {
- font-family: 'Inter var experimental';
- font-weight: 100 900;
- font-display: swap;
- font-style: oblique 0deg 10deg;
- src: url("Inter.var.woff2?v=3.15") format("woff2");
-}
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/layout/_master.tmpl b/VisualPinball.Unity/Documentation~/template/vpe/layout/_master.tmpl
new file mode 100644
index 000000000..f6bc52f5f
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/layout/_master.tmpl
@@ -0,0 +1,182 @@
+{{!Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license.}}
+{{!include(/^public/.*/)}}
+{{!include(favicon.ico)}}
+{{!include(logo.svg)}}
+{{!include(search-stopwords.json)}}
+
+
+
+
+ {{#redirect_url}}
+
+ {{/redirect_url}}
+ {{^redirect_url}}
+ {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
+
+
+ {{#_description}} {{/_description}}
+
+
+
+
+
+
+ {{#_noindex}} {{/_noindex}}
+ {{#_enableSearch}} {{/_enableSearch}}
+ {{#_disableNewTab}} {{/_disableNewTab}}
+ {{#_disableTocFilter}} {{/_disableTocFilter}}
+ {{#docurl}} {{/docurl}}
+
+
+
+
+
+
+
+
+
+
+
+ {{/redirect_url}}
+
+
+
+ {{^redirect_url}}
+
+
+
+
+ {{#_googleAnalyticsTagId}}
+
+
+ {{/_googleAnalyticsTagId}}
+
+
+
+
+
+
+
+
+
+
+
+ {{!body}}
+
+
+ {{^_disableNextArticle}}
+
+ {{/_disableNextArticle}}
+
+
+
+
+
+
+ {{^_disableContribution}}
+
+ {{/_disableContribution}}
+
+
+
+ {{#_enableSearch}}
+
+ {{/_enableSearch}}
+
+
+
+
+ {{{_appFooter}}}{{^_appFooter}}
Made with docfx {{/_appFooter}}
+
+
+
+
+
+
+
+ {{/redirect_url}}
+
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/logo.svg b/VisualPinball.Unity/Documentation~/template/vpe/logo.svg
index 6c66fa6a8..684a02604 100644
--- a/VisualPinball.Unity/Documentation~/template/vpe/logo.svg
+++ b/VisualPinball.Unity/Documentation~/template/vpe/logo.svg
@@ -1 +1,9 @@
-
\ No newline at end of file
+
+
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/partials/affix.tmpl.partial b/VisualPinball.Unity/Documentation~/template/vpe/partials/affix.tmpl.partial
deleted file mode 100644
index a31807940..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/partials/affix.tmpl.partial
+++ /dev/null
@@ -1,25 +0,0 @@
-{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
-
-
-
- {{^_disableContribution}}
-
- {{/_disableContribution}}
-
-
-
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/partials/head.tmpl.partial b/VisualPinball.Unity/Documentation~/template/vpe/partials/head.tmpl.partial
deleted file mode 100644
index f63967c0a..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/partials/head.tmpl.partial
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
- {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/partials/logo.tmpl.partial b/VisualPinball.Unity/Documentation~/template/vpe/partials/logo.tmpl.partial
deleted file mode 100644
index 1bb847c87..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/partials/logo.tmpl.partial
+++ /dev/null
@@ -1,5 +0,0 @@
-{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
-
-
-
-
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/partials/navbar.tmpl.partial b/VisualPinball.Unity/Documentation~/template/vpe/partials/navbar.tmpl.partial
deleted file mode 100644
index 7f5e48e0c..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/partials/navbar.tmpl.partial
+++ /dev/null
@@ -1,20 +0,0 @@
-{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
-
-
-
-
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.css b/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.css
new file mode 100644
index 000000000..175b1ce3a
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.css
@@ -0,0 +1 @@
+.basicLightbox{position:fixed;display:flex;justify-content:center;align-items:center;top:0;left:0;width:100%;height:100vh;background:rgba(0,0,0,.8);opacity:.01;transition:opacity .4s ease;z-index:1000;will-change:opacity}.basicLightbox--visible{opacity:1}.basicLightbox__placeholder{max-width:100%;transform:scale(.9);transition:transform .4s ease;z-index:1;will-change:transform}.basicLightbox__placeholder>iframe:first-child:last-child,.basicLightbox__placeholder>img:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{display:block;position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;max-width:95%;max-height:95%}.basicLightbox__placeholder>iframe:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{pointer-events:auto}.basicLightbox__placeholder>img:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{width:auto;height:auto}.basicLightbox--iframe .basicLightbox__placeholder,.basicLightbox--img .basicLightbox__placeholder,.basicLightbox--video .basicLightbox__placeholder{width:100%;height:100%;pointer-events:none}.basicLightbox--visible .basicLightbox__placeholder{transform:scale(1)}
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.js b/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.js
new file mode 100644
index 000000000..b2b6ccd57
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/public/basicLightbox.min.js
@@ -0,0 +1 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).basicLightbox=e()}}((function(){return function e(n,t,o){function r(c,u){if(!t[c]){if(!n[c]){var s="function"==typeof require&&require;if(!u&&s)return s(c,!0);if(i)return i(c,!0);var a=new Error("Cannot find module '"+c+"'");throw a.code="MODULE_NOT_FOUND",a}var l=t[c]={exports:{}};n[c][0].call(l.exports,(function(e){return r(n[c][1][e]||e)}),l,l.exports,e,n,t,o)}return t[c].exports}for(var i="function"==typeof require&&require,c=0;c1&&void 0!==arguments[1]&&arguments[1],t=document.createElement("div");return t.innerHTML=e.trim(),!0===n?t.children:t.firstChild},r=function(e,n){var t=e.children;return 1===t.length&&t[0].tagName===n},i=function(e){return null!=(e=e||document.querySelector(".basicLightbox"))&&!0===e.ownerDocument.body.contains(e)};t.visible=i;t.create=function(e,n){var t=function(e,n){var t=o('\n\t\t\n\t')),i=t.querySelector(".basicLightbox__placeholder");e.forEach((function(e){return i.appendChild(e)}));var c=r(i,"IMG"),u=r(i,"VIDEO"),s=r(i,"IFRAME");return!0===c&&t.classList.add("basicLightbox--img"),!0===u&&t.classList.add("basicLightbox--video"),!0===s&&t.classList.add("basicLightbox--iframe"),t}(e=function(e){var n="string"==typeof e,t=e instanceof HTMLElement==1;if(!1===n&&!1===t)throw new Error("Content must be a DOM element/node or string");return!0===n?Array.from(o(e,!0)):"TEMPLATE"===e.tagName?[e.content.cloneNode(!0)]:Array.from(e.children)}(e),n=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(null==(e=Object.assign({},e)).closable&&(e.closable=!0),null==e.className&&(e.className=""),null==e.onShow&&(e.onShow=function(){}),null==e.onClose&&(e.onClose=function(){}),"boolean"!=typeof e.closable)throw new Error("Property `closable` must be a boolean");if("string"!=typeof e.className)throw new Error("Property `className` must be a string");if("function"!=typeof e.onShow)throw new Error("Property `onShow` must be a function");if("function"!=typeof e.onClose)throw new Error("Property `onClose` must be a function");return e}(n)),c=function(e){return!1!==n.onClose(u)&&function(e,n){return e.classList.remove("basicLightbox--visible"),setTimeout((function(){return!1===i(e)||e.parentElement.removeChild(e),n()}),410),!0}(t,(function(){if("function"==typeof e)return e(u)}))};!0===n.closable&&t.addEventListener("click",(function(e){e.target===t&&c()}));var u={element:function(){return t},visible:function(){return i(t)},show:function(e){return!1!==n.onShow(u)&&function(e,n){return document.body.appendChild(e),setTimeout((function(){requestAnimationFrame((function(){return e.classList.add("basicLightbox--visible"),n()}))}),10),!0}(t,(function(){if("function"==typeof e)return e(u)}))},close:c};return u}},{}]},{},[1])(1)}));
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/public/fonts.css b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts.css
new file mode 100644
index 000000000..c0ee3259e
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts.css
@@ -0,0 +1,201 @@
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 100;
+ font-display: swap;
+ src: url("fonts/Inter-Thin.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Thin.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 100;
+ font-display: swap;
+ src: url("fonts/Inter-ThinItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-ThinItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 200;
+ font-display: swap;
+ src: url("fonts/Inter-ExtraLight.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-ExtraLight.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 200;
+ font-display: swap;
+ src: url("fonts/Inter-ExtraLightItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-ExtraLightItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 300;
+ font-display: swap;
+ src: url("fonts/Inter-Light.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Light.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 300;
+ font-display: swap;
+ src: url("fonts/Inter-LightItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-LightItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: url("fonts/Inter-Regular.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Regular.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 400;
+ font-display: swap;
+ src: url("fonts/Inter-Italic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Italic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 500;
+ font-display: swap;
+ src: url("fonts/Inter-Medium.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Medium.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 500;
+ font-display: swap;
+ src: url("fonts/Inter-MediumItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-MediumItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 600;
+ font-display: swap;
+ src: url("fonts/Inter-SemiBold.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-SemiBold.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 600;
+ font-display: swap;
+ src: url("fonts/Inter-SemiBoldItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-SemiBoldItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: url("fonts/Inter-Bold.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Bold.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 700;
+ font-display: swap;
+ src: url("fonts/Inter-BoldItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-BoldItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 800;
+ font-display: swap;
+ src: url("fonts/Inter-ExtraBold.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-ExtraBold.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 800;
+ font-display: swap;
+ src: url("fonts/Inter-ExtraBoldItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-ExtraBoldItalic.woff?v=3.15") format("woff");
+}
+
+@font-face {
+ font-family: 'Inter';
+ font-style: normal;
+ font-weight: 900;
+ font-display: swap;
+ src: url("fonts/Inter-Black.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-Black.woff?v=3.15") format("woff");
+}
+@font-face {
+ font-family: 'Inter';
+ font-style: italic;
+ font-weight: 900;
+ font-display: swap;
+ src: url("fonts/Inter-BlackItalic.woff2?v=3.15") format("woff2"),
+ url("fonts/Inter-BlackItalic.woff?v=3.15") format("woff");
+}
+
+/* -------------------------------------------------------
+Variable font.
+Usage:
+
+ html { font-family: 'Inter', sans-serif; }
+ @supports (font-variation-settings: normal) {
+ html { font-family: 'Inter var', sans-serif; }
+ }
+*/
+@font-face {
+ font-family: 'Inter var';
+ font-weight: 100 900;
+ font-display: swap;
+ font-style: normal;
+ font-named-instance: 'Regular';
+ src: url("fonts/Inter-roman.var.woff2?v=3.15") format("woff2");
+}
+@font-face {
+ font-family: 'Inter var';
+ font-weight: 100 900;
+ font-display: swap;
+ font-style: italic;
+ font-named-instance: 'Italic';
+ src: url("fonts/Inter-italic.var.woff2?v=3.15") format("woff2");
+}
+
+
+/* --------------------------------------------------------------------------
+[EXPERIMENTAL] Multi-axis, single variable font.
+
+Slant axis is not yet widely supported (as of February 2019) and thus this
+multi-axis single variable font is opt-in rather than the default.
+
+When using this, you will probably need to set font-variation-settings
+explicitly, e.g.
+
+ * { font-variation-settings: "slnt" 0deg }
+ .italic { font-variation-settings: "slnt" 10deg }
+
+*/
+@font-face {
+ font-family: 'Inter var experimental';
+ font-weight: 100 900;
+ font-display: swap;
+ font-style: oblique 0deg 10deg;
+ src: url("fonts/Inter.var.woff2?v=3.15") format("woff2");
+}
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Black.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Black.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Black.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Black.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Black.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Black.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Black.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Black.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BlackItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BlackItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BlackItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BlackItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BlackItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BlackItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BlackItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BlackItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Bold.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Bold.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Bold.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Bold.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Bold.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Bold.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Bold.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Bold.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BoldItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BoldItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BoldItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BoldItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BoldItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BoldItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-BoldItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-BoldItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBold.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBold.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBold.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBold.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBold.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBold.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBold.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBold.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBoldItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBoldItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBoldItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBoldItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBoldItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBoldItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraBoldItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraBoldItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLight.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLight.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLight.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLight.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLight.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLight.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLight.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLight.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLightItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLightItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLightItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLightItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLightItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLightItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ExtraLightItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ExtraLightItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Italic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Italic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Italic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Italic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Italic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Italic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Italic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Italic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Light.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Light.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Light.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Light.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Light.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Light.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Light.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Light.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-LightItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-LightItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-LightItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-LightItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-LightItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-LightItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-LightItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-LightItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Medium.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Medium.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Medium.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Medium.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Medium.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Medium.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Medium.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Medium.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-MediumItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-MediumItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-MediumItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-MediumItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-MediumItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-MediumItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-MediumItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-MediumItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Regular.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Regular.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Regular.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Regular.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Regular.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Regular.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Regular.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Regular.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBold.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBold.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBold.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBold.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBold.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBold.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBold.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBold.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBoldItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBoldItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBoldItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBoldItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBoldItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBoldItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-SemiBoldItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-SemiBoldItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Thin.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Thin.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Thin.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Thin.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Thin.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Thin.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-Thin.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-Thin.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ThinItalic.woff b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ThinItalic.woff
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ThinItalic.woff
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ThinItalic.woff
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ThinItalic.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ThinItalic.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-ThinItalic.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-ThinItalic.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-italic.var.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-italic.var.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-italic.var.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-italic.var.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-roman.var.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-roman.var.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter-roman.var.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter-roman.var.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter.var.woff2 b/VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter.var.woff2
similarity index 100%
rename from VisualPinball.Unity/Documentation~/template/vpe/fonts/Inter.var.woff2
rename to VisualPinball.Unity/Documentation~/template/vpe/public/fonts/Inter.var.woff2
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/public/main.css b/VisualPinball.Unity/Documentation~/template/vpe/public/main.css
new file mode 100644
index 000000000..bdf06c3fd
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/public/main.css
@@ -0,0 +1,131 @@
+@import url("fonts.css");
+@import url("https://raw.githubusercontent.com/thomaspark/bootswatch/v5/dist/zephyr/bootstrap.min.css");
+
+/* layout */
+.navbar-github { /* align github link to the right */
+ order: 100;
+ margin-left: 10px;
+ margin-top: 4px;
+}
+.navbar-github > svg { /* github logo color */
+ fill: #ccc;
+}
+body[data-layout=landing]>main { /* landing page full width */
+ display: block;
+}
+#vpe-halftone { /* landing page logo width */
+ max-width: 720px;
+ display: block;
+}
+
+/* color overrides */
+:root,
+[data-bs-theme=light] {
+ --bs-font-sans-serif: Inter, 'Segoe UI', Tahoma, Helvetica, sans-serif;
+ --bs-body-font-family: var(--bs-font-sans-serif);
+ --bs-link-color-rgb: 214, 99, 22 !important;
+ --bs-link-hover-color-rgb: 183, 74, 0 !important;
+ --bs-code-color: rgb(var(--bs-link-color-rgb), 1);
+ --vpe-body-bg-secondary: #f3f3f3;
+ --vpe-link-secondary: #00000080;
+ --vpe-link-secondary-hover: #000000aa;
+ --vpe-body-color-less-contrast: rgba(33, 37, 41, 0.5)
+}
+[data-bs-theme=dark] {
+ --bs-link-color-rgb: 236, 132, 61 !important;
+ --vpe-body-bg-secondary: #292e33;
+ --vpe-link-secondary: #ffffff80;
+ --vpe-link-secondary-hover: #ffffffaa;
+ --vpe-body-color-less-contrast: rgba(222, 226, 230, 0.5)
+}
+[data-bs-theme=dark] header { /* header slightly lighter in dark mode */
+ background-color: var(--vpe-body-bg-secondary) !important;
+}
+
+/* fix theme toggle button color */
+[data-bs-theme=light] header .dropdown a:hover,
+[data-bs-theme=light] header .dropdown a:active,
+[data-bs-theme=light] header .dropdown a:focus-visible,
+[data-bs-theme=light] header .dropdown a:focus,
+[data-bs-theme=light] header .btn.show {
+ color: white !important;
+}
+
+/* don't underline links */
+a {
+ text-decoration: none !important;
+}
+
+/* zephyr fixes */
+.btn-outline-secondary { /* outline button */
+ color: var(--bs-secondary-color) !important;
+}
+[data-bs-theme=dark] .btn-outline-secondary:hover { /* outline button hover */
+ color: var(--bs-body-bg) !important;
+}
+.link-secondary { /* TOC links on the left */
+ color: var(--vpe-link-secondary) !important;
+}
+.link-secondary:hover {
+ color: var(--vpe-link-secondary-hover) !important;
+}
+#search-results > .sr-items .sr-item > .item-href { /* search result colors */
+ color: rgba(var(--bs-link-color-rgb), 0.6);
+}
+
+[data-bs-theme=light] i.bi.bi-search { /* search icon color */
+ color: white;
+}
+
+/* landing svg art colors */
+svg #text { /* visual pinball engine */
+ fill: var(--bs-body-color);
+}
+svg #bg1 { /* outer */
+ stroke-width: 0;
+ fill: var(--bs-body-bg)
+}
+svg #logo { /* logo */
+ fill: var(--bs-body-color);
+}
+svg #bg2 { /* inner */
+ fill: var(--vpe-body-bg-secondary);
+}
+
+/* footer customization */
+body>footer, body[data-layout=landing]>footer { /* footer height */
+ color: var(--vpe-body-color-less-contrast) !important;
+ background-color: var(--vpe-body-bg-secondary);
+ font-size: 0.8rem !important;
+ height: 52px;
+ padding-left: 10px;
+}
+
+/* make titles bold */
+h1, h2 {
+ font-weight: bold;
+}
+
+/* make tables striped */
+table.table.table-bordered > tbody > tr:nth-of-type(odd) > td {
+ background-color: var(--vpe-body-bg-secondary);
+}
+table.table.table-bordered > thead > tr > th { /* separate column header */
+ border-bottom-width: 3px;
+}
+table.table.table-bordered > * > tr > *:nth-child(1) { /* separate row header */
+ border-right-width: 3px;
+ font-style: italic;
+}
+
+/* code colors */
+code {
+ background-color: rgb(var(--bs-link-color-rgb), 0.15);
+ padding: 1px 3px;
+ border-radius: 3px;
+}
+
+/* image hover cursor */
+img:not(#logo):hover {
+ cursor: zoom-in;
+}
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/public/zephyr.css b/VisualPinball.Unity/Documentation~/template/vpe/public/zephyr.css
new file mode 100644
index 000000000..732b3c4ca
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/public/zephyr.css
@@ -0,0 +1,12286 @@
+/* this is just for reference. inlcuded is the minified version directly from github.
+ * https://github.com/thomaspark/bootswatch/tree/v5/dist/zephyr
+ */
+
+@charset "UTF-8";
+/*!
+ * Bootswatch v5.3.2 (https://bootswatch.com)
+ * Theme: zephyr
+ * Copyright 2012-2023 Thomas Park
+ * Licensed under MIT
+ * Based on Bootstrap
+*/
+/*!
+ * Bootstrap v5.3.2 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+:root,
+[data-bs-theme=light] {
+ --bs-blue: #3459e6;
+ --bs-indigo: #6610f2;
+ --bs-purple: #6f42c1;
+ --bs-pink: #d63384;
+ --bs-red: #da292e;
+ --bs-orange: #f8765f;
+ --bs-yellow: #f4bd61;
+ --bs-green: #2fb380;
+ --bs-teal: #20c997;
+ --bs-cyan: #287bb5;
+ --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: #3459e6;
+ --bs-secondary: #fff;
+ --bs-success: #2fb380;
+ --bs-info: #287bb5;
+ --bs-warning: #f4bd61;
+ --bs-danger: #da292e;
+ --bs-light: #f8f9fa;
+ --bs-dark: #212529;
+ --bs-primary-rgb: 52, 89, 230;
+ --bs-secondary-rgb: 255, 255, 255;
+ --bs-success-rgb: 47, 179, 128;
+ --bs-info-rgb: 40, 123, 181;
+ --bs-warning-rgb: 244, 189, 97;
+ --bs-danger-rgb: 218, 41, 46;
+ --bs-light-rgb: 248, 249, 250;
+ --bs-dark-rgb: 33, 37, 41;
+ --bs-primary-text-emphasis: #15245c;
+ --bs-secondary-text-emphasis: #666666;
+ --bs-success-text-emphasis: #134833;
+ --bs-info-text-emphasis: #103148;
+ --bs-warning-text-emphasis: #624c27;
+ --bs-danger-text-emphasis: #571012;
+ --bs-light-text-emphasis: #495057;
+ --bs-dark-text-emphasis: #495057;
+ --bs-primary-bg-subtle: #d6defa;
+ --bs-secondary-bg-subtle: white;
+ --bs-success-bg-subtle: #d5f0e6;
+ --bs-info-bg-subtle: #d4e5f0;
+ --bs-warning-bg-subtle: #fdf2df;
+ --bs-danger-bg-subtle: #f8d4d5;
+ --bs-light-bg-subtle: #fcfcfd;
+ --bs-dark-bg-subtle: #ced4da;
+ --bs-primary-border-subtle: #aebdf5;
+ --bs-secondary-border-subtle: white;
+ --bs-success-border-subtle: #ace1cc;
+ --bs-info-border-subtle: #a9cae1;
+ --bs-warning-border-subtle: #fbe5c0;
+ --bs-danger-border-subtle: #f0a9ab;
+ --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, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
+ --bs-body-font-family: var(--bs-font-sans-serif);
+ --bs-body-font-size: 1rem;
+ --bs-body-font-weight: 400;
+ --bs-body-line-height: 1.5;
+ --bs-body-color: #495057;
+ --bs-body-color-rgb: 73, 80, 87;
+ --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(73, 80, 87, 0.75);
+ --bs-secondary-color-rgb: 73, 80, 87;
+ --bs-secondary-bg: #e9ecef;
+ --bs-secondary-bg-rgb: 233, 236, 239;
+ --bs-tertiary-color: rgba(73, 80, 87, 0.5);
+ --bs-tertiary-color-rgb: 73, 80, 87;
+ --bs-tertiary-bg: #f8f9fa;
+ --bs-tertiary-bg-rgb: 248, 249, 250;
+ --bs-heading-color: var(--bs-primary-color);
+ --bs-link-color: #3459e6;
+ --bs-link-color-rgb: 214, 99, 22;
+ --bs-link-decoration: underline;
+ --bs-link-hover-color: #2a47b8;
+ --bs-link-hover-color-rgb: 42, 71, 184;
+ --bs-code-color: #d63384;
+ --bs-highlight-color: #495057;
+ --bs-highlight-bg: #fdf2df;
+ --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.375rem;
+ --bs-border-radius-sm: 0.25rem;
+ --bs-border-radius-lg: 0.5rem;
+ --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 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ --bs-box-shadow-lg: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+ --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(52, 89, 230, 0.25);
+ --bs-form-valid-color: #2fb380;
+ --bs-form-valid-border-color: #2fb380;
+ --bs-form-invalid-color: #da292e;
+ --bs-form-invalid-border-color: #da292e;
+}
+
+[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: #859bf0;
+ --bs-secondary-text-emphasis: white;
+ --bs-success-text-emphasis: #82d1b3;
+ --bs-info-text-emphasis: #7eb0d3;
+ --bs-warning-text-emphasis: #f8d7a0;
+ --bs-danger-text-emphasis: #e97f82;
+ --bs-light-text-emphasis: #f8f9fa;
+ --bs-dark-text-emphasis: #dee2e6;
+ --bs-primary-bg-subtle: #0a122e;
+ --bs-secondary-bg-subtle: #333333;
+ --bs-success-bg-subtle: #09241a;
+ --bs-info-bg-subtle: #081924;
+ --bs-warning-bg-subtle: #312613;
+ --bs-danger-bg-subtle: #2c0809;
+ --bs-light-bg-subtle: #343a40;
+ --bs-dark-bg-subtle: #1a1d20;
+ --bs-primary-border-subtle: #1f358a;
+ --bs-secondary-border-subtle: #999999;
+ --bs-success-border-subtle: #1c6b4d;
+ --bs-info-border-subtle: #184a6d;
+ --bs-warning-border-subtle: #92713a;
+ --bs-danger-border-subtle: #83191c;
+ --bs-light-border-subtle: #495057;
+ --bs-dark-border-subtle: #343a40;
+ --bs-heading-color: inherit;
+ --bs-link-color: #859bf0;
+ --bs-link-hover-color: #9daff3;
+ --bs-link-color-rgb: 133, 155, 240;
+ --bs-link-hover-color-rgb: 157, 175, 243;
+ --bs-code-color: #e685b5;
+ --bs-highlight-color: #dee2e6;
+ --bs-highlight-bg: #624c27;
+ --bs-border-color: #495057;
+ --bs-border-color-translucent: rgba(255, 255, 255, 0.15);
+ --bs-form-valid-color: #82d1b3;
+ --bs-form-valid-border-color: #82d1b3;
+ --bs-form-invalid-color: #e97f82;
+ --bs-form-invalid-border-color: #e97f82;
+}
+
+*,
+*::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: 0.25;
+}
+
+h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ line-height: 1.2;
+ color: var(--bs-heading-color);
+}
+
+h1, .h1 {
+ font-size: calc(1.375rem + 1.5vw);
+}
+@media (min-width: 1200px) {
+ h1, .h1 {
+ font-size: 2.5rem;
+ }
+}
+
+h2, .h2 {
+ font-size: calc(1.325rem + 0.9vw);
+}
+@media (min-width: 1200px) {
+ h2, .h2 {
+ font-size: 2rem;
+ }
+}
+
+h3, .h3 {
+ font-size: calc(1.3rem + 0.6vw);
+}
+@media (min-width: 1200px) {
+ h3, .h3 {
+ font-size: 1.75rem;
+ }
+}
+
+h4, .h4 {
+ font-size: calc(1.275rem + 0.3vw);
+}
+@media (min-width: 1200px) {
+ h4, .h4 {
+ font-size: 1.5rem;
+ }
+}
+
+h5, .h5 {
+ font-size: 1.25rem;
+}
+
+h6, .h6 {
+ font-size: 1rem;
+}
+
+p {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+abbr[title] {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+ cursor: help;
+ -webkit-text-decoration-skip-ink: none;
+ text-decoration-skip-ink: none;
+}
+
+address {
+ margin-bottom: 1rem;
+ font-style: normal;
+ line-height: inherit;
+}
+
+ol,
+ul {
+ padding-left: 2rem;
+}
+
+ol,
+ul,
+dl {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: 700;
+}
+
+dd {
+ margin-bottom: 0.5rem;
+ margin-left: 0;
+}
+
+blockquote {
+ margin: 0 0 1rem;
+}
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+small, .small {
+ font-size: 0.875em;
+}
+
+mark, .mark {
+ padding: 0.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: 0.1875rem 0.375rem;
+ font-size: 0.875em;
+ color: var(--bs-body-bg);
+ background-color: var(--bs-body-color);
+ border-radius: 0.25rem;
+}
+kbd kbd {
+ padding: 0;
+ font-size: 1em;
+}
+
+figure {
+ margin: 0 0 1rem;
+}
+
+img,
+svg {
+ vertical-align: middle;
+}
+
+table {
+ caption-side: bottom;
+ border-collapse: collapse;
+}
+
+caption {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+ color: var(--bs-secondary-color);
+ text-align: left;
+}
+
+th {
+ font-weight: 500;
+ text-align: inherit;
+ text-align: -webkit-match-parent;
+}
+
+thead,
+tbody,
+tfoot,
+tr,
+td,
+th {
+ border-color: inherit;
+ border-style: solid;
+ border-width: 0;
+}
+
+label {
+ display: inline-block;
+}
+
+button {
+ border-radius: 0;
+}
+
+button:focus:not(:focus-visible) {
+ outline: 0;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+button,
+select {
+ text-transform: none;
+}
+
+[role=button] {
+ cursor: pointer;
+}
+
+select {
+ word-wrap: normal;
+}
+select:disabled {
+ opacity: 1;
+}
+
+[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
+ display: none !important;
+}
+
+button,
+[type=button],
+[type=reset],
+[type=submit] {
+ -webkit-appearance: button;
+}
+button:not(:disabled),
+[type=button]:not(:disabled),
+[type=reset]:not(:disabled),
+[type=submit]:not(:disabled) {
+ cursor: pointer;
+}
+
+::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+}
+
+textarea {
+ resize: vertical;
+}
+
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+legend {
+ float: left;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 0.5rem;
+ font-size: calc(1.275rem + 0.3vw);
+ line-height: inherit;
+}
+@media (min-width: 1200px) {
+ legend {
+ font-size: 1.5rem;
+ }
+}
+legend + * {
+ clear: left;
+}
+
+::-webkit-datetime-edit-fields-wrapper,
+::-webkit-datetime-edit-text,
+::-webkit-datetime-edit-minute,
+::-webkit-datetime-edit-hour-field,
+::-webkit-datetime-edit-day-field,
+::-webkit-datetime-edit-month-field,
+::-webkit-datetime-edit-year-field {
+ padding: 0;
+}
+
+::-webkit-inner-spin-button {
+ height: auto;
+}
+
+[type=search] {
+ -webkit-appearance: textfield;
+ outline-offset: -2px;
+}
+
+/* rtl:raw:
+[type="tel"],
+[type="url"],
+[type="email"],
+[type="number"] {
+ direction: ltr;
+}
+*/
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+::-webkit-color-swatch-wrapper {
+ padding: 0;
+}
+
+::-webkit-file-upload-button {
+ font: inherit;
+ -webkit-appearance: button;
+}
+
+::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.25rem;
+ font-weight: 300;
+}
+
+.display-1 {
+ font-size: calc(1.625rem + 4.5vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-1 {
+ font-size: 5rem;
+ }
+}
+
+.display-2 {
+ font-size: calc(1.575rem + 3.9vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-2 {
+ font-size: 4.5rem;
+ }
+}
+
+.display-3 {
+ font-size: calc(1.525rem + 3.3vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-3 {
+ font-size: 4rem;
+ }
+}
+
+.display-4 {
+ font-size: calc(1.475rem + 2.7vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-4 {
+ font-size: 3.5rem;
+ }
+}
+
+.display-5 {
+ font-size: calc(1.425rem + 2.1vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-5 {
+ font-size: 3rem;
+ }
+}
+
+.display-6 {
+ font-size: calc(1.375rem + 1.5vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-6 {
+ font-size: 2.5rem;
+ }
+}
+
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline-item {
+ display: inline-block;
+}
+.list-inline-item:not(:last-child) {
+ margin-right: 0.5rem;
+}
+
+.initialism {
+ font-size: 0.875em;
+ text-transform: uppercase;
+}
+
+.blockquote {
+ margin-bottom: 1rem;
+ font-size: 1.25rem;
+}
+.blockquote > :last-child {
+ margin-bottom: 0;
+}
+
+.blockquote-footer {
+ margin-top: -1rem;
+ margin-bottom: 1rem;
+ font-size: 0.875em;
+ color: #6c757d;
+}
+.blockquote-footer::before {
+ content: "— ";
+}
+
+.img-fluid {
+ max-width: 100%;
+ height: auto;
+}
+
+.img-thumbnail {
+ padding: 0.25rem;
+ background-color: var(--bs-body-bg);
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ box-shadow: var(--bs-box-shadow-sm);
+ max-width: 100%;
+ height: auto;
+}
+
+.figure {
+ display: inline-block;
+}
+
+.figure-img {
+ margin-bottom: 0.5rem;
+ line-height: 1;
+}
+
+.figure-caption {
+ font-size: 0.875em;
+ color: 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) * 0.5);
+ padding-left: calc(var(--bs-gutter-x) * 0.5);
+ margin-right: auto;
+ margin-left: auto;
+}
+
+@media (min-width: 576px) {
+ .container-sm, .container {
+ max-width: 540px;
+ }
+}
+@media (min-width: 768px) {
+ .container-md, .container-sm, .container {
+ max-width: 720px;
+ }
+}
+@media (min-width: 992px) {
+ .container-lg, .container-md, .container-sm, .container {
+ max-width: 960px;
+ }
+}
+@media (min-width: 1200px) {
+ .container-xl, .container-lg, .container-md, .container-sm, .container {
+ max-width: 1140px;
+ }
+}
+@media (min-width: 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) * 0.5);
+ padding-left: calc(var(--bs-gutter-x) * 0.5);
+ margin-top: var(--bs-gutter-y);
+}
+
+.col {
+ flex: 1 0 0%;
+}
+
+.row-cols-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+}
+
+.row-cols-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.row-cols-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+}
+
+.row-cols-3 > * {
+ flex: 0 0 auto;
+ width: 33.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: 1rem 1rem;
+ 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: 0.5rem 0.5rem;
+}
+
+.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: #d6defa;
+ --bs-table-border-color: #abb2c8;
+ --bs-table-striped-bg: #cbd3ee;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #c1c8e1;
+ --bs-table-active-color: #fff;
+ --bs-table-hover-bg: #c6cde7;
+ --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: white;
+ --bs-table-border-color: #cccccc;
+ --bs-table-striped-bg: #f2f2f2;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #e6e6e6;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #ececec;
+ --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: #d5f0e6;
+ --bs-table-border-color: #aac0b8;
+ --bs-table-striped-bg: #cae4db;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #c0d8cf;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #c5ded5;
+ --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: #d4e5f0;
+ --bs-table-border-color: #aab7c0;
+ --bs-table-striped-bg: #c9dae4;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #bfced8;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #c4d4de;
+ --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: #fdf2df;
+ --bs-table-border-color: #cac2b2;
+ --bs-table-striped-bg: #f0e6d4;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #e4dac9;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #eae0ce;
+ --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: #f8d4d5;
+ --bs-table-border-color: #c6aaaa;
+ --bs-table-striped-bg: #ecc9ca;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #dfbfc0;
+ --bs-table-active-color: #fff;
+ --bs-table-hover-bg: #e5c4c5;
+ --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: 0.5rem;
+ font-weight: 500;
+}
+
+.col-form-label {
+ padding-top: calc(0.5rem + var(--bs-border-width));
+ padding-bottom: calc(0.5rem + var(--bs-border-width));
+ margin-bottom: 0;
+ font-size: inherit;
+ font-weight: 500;
+ line-height: 1.5;
+}
+
+.col-form-label-lg {
+ padding-top: calc(0.5rem + var(--bs-border-width));
+ padding-bottom: calc(0.5rem + var(--bs-border-width));
+ font-size: 1.25rem;
+}
+
+.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.875rem;
+}
+
+.form-text {
+ margin-top: 0.25rem;
+ font-size: 0.875em;
+ color: var(--bs-secondary-color);
+}
+
+.form-control {
+ display: block;
+ width: 100%;
+ padding: 0.5rem 1rem;
+ font-size: 0.875rem;
+ font-weight: 400;
+ line-height: 1.5;
+ 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: var(--bs-border-radius);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-control {
+ transition: none;
+ }
+}
+.form-control[type=file] {
+ overflow: hidden;
+}
+.form-control[type=file]:not(:disabled):not([readonly]) {
+ cursor: pointer;
+}
+.form-control:focus {
+ color: var(--bs-body-color);
+ background-color: var(--bs-body-bg);
+ border-color: #9aacf3;
+ outline: 0;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 0 0 0.25rem rgba(52, 89, 230, 0.25);
+}
+.form-control::-webkit-date-and-time-value {
+ min-width: 85px;
+ height: 1.5em;
+ 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::-webkit-file-upload-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+ 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;
+ -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+.form-control::file-selector-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+ 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;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-control::-webkit-file-upload-button {
+ -webkit-transition: none;
+ transition: none;
+ }
+ .form-control::file-selector-button {
+ transition: none;
+ }
+}
+.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
+ background-color: var(--bs-secondary-bg);
+}
+.form-control:hover:not(:disabled):not([readonly])::file-selector-button {
+ background-color: var(--bs-secondary-bg);
+}
+
+.form-control-plaintext {
+ display: block;
+ width: 100%;
+ padding: 0.5rem 0;
+ margin-bottom: 0;
+ line-height: 1.5;
+ color: var(--bs-body-color);
+ background-color: transparent;
+ border: solid transparent;
+ 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.5em + 0.5rem + calc(var(--bs-border-width) * 2));
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ border-radius: var(--bs-border-radius-sm);
+}
+.form-control-sm::-webkit-file-upload-button {
+ padding: 0.25rem 0.5rem;
+ margin: -0.25rem -0.5rem;
+ -webkit-margin-end: 0.5rem;
+ margin-inline-end: 0.5rem;
+}
+.form-control-sm::file-selector-button {
+ padding: 0.25rem 0.5rem;
+ margin: -0.25rem -0.5rem;
+ -webkit-margin-end: 0.5rem;
+ margin-inline-end: 0.5rem;
+}
+
+.form-control-lg {
+ min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ border-radius: var(--bs-border-radius-lg);
+}
+.form-control-lg::-webkit-file-upload-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+}
+.form-control-lg::file-selector-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+}
+
+textarea.form-control {
+ min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
+}
+textarea.form-control-sm {
+ min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));
+}
+textarea.form-control-lg {
+ min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
+}
+
+.form-control-color {
+ width: 3rem;
+ height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));
+ padding: 0.5rem;
+}
+.form-control-color:not(:disabled):not([readonly]) {
+ cursor: pointer;
+}
+.form-control-color::-moz-color-swatch {
+ border: 0 !important;
+ border-radius: var(--bs-border-radius);
+}
+.form-control-color::-webkit-color-swatch {
+ border: 0 !important;
+ border-radius: var(--bs-border-radius);
+}
+.form-control-color.form-control-sm {
+ height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));
+}
+.form-control-color.form-control-lg {
+ height: calc(1.5em + 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: 0.5rem 3rem 0.5rem 1rem;
+ font-size: 0.875rem;
+ font-weight: 400;
+ line-height: 1.5;
+ 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 1rem center;
+ background-size: 16px 12px;
+ border: var(--bs-border-width) solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ box-shadow: var(--bs-box-shadow-inset);
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-select {
+ transition: none;
+ }
+}
+.form-select:focus {
+ border-color: #9aacf3;
+ outline: 0;
+ box-shadow: var(--bs-box-shadow-inset), 0 0 0 0.25rem rgba(52, 89, 230, 0.25);
+}
+.form-select[multiple], .form-select[size]:not([size="1"]) {
+ padding-right: 1rem;
+ background-image: none;
+}
+.form-select:disabled {
+ background-color: var(--bs-secondary-bg);
+}
+.form-select:-moz-focusring {
+ color: transparent;
+ text-shadow: 0 0 0 var(--bs-body-color);
+}
+
+.form-select-sm {
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 0.5rem;
+ font-size: 0.875rem;
+ border-radius: var(--bs-border-radius-sm);
+}
+
+.form-select-lg {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ padding-left: 1rem;
+ font-size: 1.25rem;
+ border-radius: var(--bs-border-radius-lg);
+}
+
+[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.5rem;
+ padding-left: 1.5em;
+ margin-bottom: 0.125rem;
+}
+.form-check .form-check-input {
+ float: left;
+ margin-left: -1.5em;
+}
+
+.form-check-reverse {
+ padding-right: 1.5em;
+ padding-left: 0;
+ text-align: right;
+}
+.form-check-reverse .form-check-input {
+ float: right;
+ margin-right: -1.5em;
+ margin-left: 0;
+}
+
+.form-check-input {
+ --bs-form-check-bg: var(--bs-body-bg);
+ flex-shrink: 0;
+ width: 1em;
+ height: 1em;
+ margin-top: 0.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;
+ color-adjust: exact;
+ print-color-adjust: exact;
+}
+.form-check-input[type=checkbox] {
+ border-radius: 0.25em;
+}
+.form-check-input[type=radio] {
+ border-radius: 50%;
+}
+.form-check-input:active {
+ filter: brightness(90%);
+}
+.form-check-input:focus {
+ border-color: #9aacf3;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(52, 89, 230, 0.25);
+}
+.form-check-input:checked {
+ background-color: #3459e6;
+ border-color: #3459e6;
+}
+.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: #3459e6;
+ border-color: #3459e6;
+ --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: 0.5;
+}
+.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {
+ cursor: default;
+ opacity: 0.5;
+}
+
+.form-switch {
+ padding-left: 2.5em;
+}
+.form-switch .form-check-input {
+ --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: 2em;
+ transition: background-position 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-switch .form-check-input {
+ transition: none;
+ }
+}
+.form-switch .form-check-input:focus {
+ --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='%239aacf3'/%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: 0.65;
+}
+
+[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: transparent;
+}
+.form-range:focus {
+ outline: 0;
+}
+.form-range:focus::-webkit-slider-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(52, 89, 230, 0.25);
+}
+.form-range:focus::-moz-range-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(52, 89, 230, 0.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: #3459e6;
+ border: 0;
+ border-radius: 1rem;
+ box-shadow: 0 0.1rem 0.25rem rgba(0, 0, 0, 0.1);
+ -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-range::-webkit-slider-thumb {
+ -webkit-transition: none;
+ transition: none;
+ }
+}
+.form-range::-webkit-slider-thumb:active {
+ background-color: #c2cdf8;
+}
+.form-range::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: var(--bs-secondary-bg);
+ border-color: transparent;
+ border-radius: 1rem;
+ box-shadow: var(--bs-box-shadow-inset);
+}
+.form-range::-moz-range-thumb {
+ width: 1rem;
+ height: 1rem;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: #3459e6;
+ border: 0;
+ border-radius: 1rem;
+ box-shadow: 0 0.1rem 0.25rem rgba(0, 0, 0, 0.1);
+ -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-range::-moz-range-thumb {
+ -moz-transition: none;
+ transition: none;
+ }
+}
+.form-range::-moz-range-thumb:active {
+ background-color: #c2cdf8;
+}
+.form-range::-moz-range-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: var(--bs-secondary-bg);
+ border-color: transparent;
+ border-radius: 1rem;
+ box-shadow: var(--bs-box-shadow-inset);
+}
+.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 1rem;
+ overflow: hidden;
+ text-align: start;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ pointer-events: none;
+ border: var(--bs-border-width) solid transparent;
+ transform-origin: 0 0;
+ transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-floating > label {
+ transition: none;
+ }
+}
+.form-floating > .form-control,
+.form-floating > .form-control-plaintext {
+ padding: 1rem 1rem;
+}
+.form-floating > .form-control::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder {
+ color: transparent;
+}
+.form-floating > .form-control::placeholder,
+.form-floating > .form-control-plaintext::placeholder {
+ color: transparent;
+}
+.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-control:focus, .form-floating > .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: 0.625rem;
+}
+.form-floating > .form-control:-webkit-autofill,
+.form-floating > .form-control-plaintext:-webkit-autofill {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-select {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {
+ 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 0.5rem;
+ z-index: -1;
+ height: 1.5em;
+ content: "";
+ background-color: var(--bs-body-bg);
+ border-radius: var(--bs-border-radius);
+}
+.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 0.5rem;
+ z-index: -1;
+ height: 1.5em;
+ content: "";
+ background-color: var(--bs-body-bg);
+ border-radius: var(--bs-border-radius);
+}
+.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: 0.5rem 1rem;
+ font-size: 0.875rem;
+ font-weight: 400;
+ line-height: 1.5;
+ 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);
+ border-radius: var(--bs-border-radius);
+}
+
+.input-group-lg > .form-control,
+.input-group-lg > .form-select,
+.input-group-lg > .input-group-text,
+.input-group-lg > .btn {
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ border-radius: var(--bs-border-radius-lg);
+}
+
+.input-group-sm > .form-control,
+.input-group-sm > .form-select,
+.input-group-sm > .input-group-text,
+.input-group-sm > .btn {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ border-radius: var(--bs-border-radius-sm);
+}
+
+.input-group-lg > .form-select,
+.input-group-sm > .form-select {
+ padding-right: 4rem;
+}
+
+.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
+.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3),
+.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control,
+.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
+.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4),
+.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control,
+.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: calc(var(--bs-border-width) * -1);
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.input-group > .form-floating:not(:first-child) > .form-control,
+.input-group > .form-floating:not(:first-child) > .form-select {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.valid-feedback {
+ display: none;
+ width: 100%;
+ margin-top: 0.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: 0.25rem 0.5rem;
+ margin-top: 0.1rem;
+ font-size: 0.875rem;
+ color: #fff;
+ background-color: var(--bs-success);
+ border-radius: var(--bs-border-radius);
+}
+
+.was-validated :valid ~ .valid-feedback,
+.was-validated :valid ~ .valid-tooltip,
+.is-valid ~ .valid-feedback,
+.is-valid ~ .valid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:valid, .form-control.is-valid {
+ border-color: var(--bs-form-valid-border-color);
+ padding-right: calc(1.5em + 1rem);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%232fb380' 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.375em + 0.25rem) center;
+ background-size: calc(0.75em + 0.5rem) calc(0.75em + 0.5rem);
+}
+.was-validated .form-control:valid:focus, .form-control.is-valid:focus {
+ border-color: var(--bs-form-valid-border-color);
+ box-shadow: 0 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.5em + 1rem);
+ background-position: top calc(0.375em + 0.25rem) right calc(0.375em + 0.25rem);
+}
+
+.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='%232fb380' 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: 5.5rem;
+ background-position: right 1rem center, center right 3rem;
+ background-size: 16px 12px, calc(0.75em + 0.5rem) calc(0.75em + 0.5rem);
+}
+.was-validated .form-select:valid:focus, .form-select.is-valid:focus {
+ border-color: var(--bs-form-valid-border-color);
+ box-shadow: 0 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.5em + 1rem));
+}
+
+.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 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: 0.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: 0.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: 0.25rem 0.5rem;
+ margin-top: 0.1rem;
+ font-size: 0.875rem;
+ color: #fff;
+ background-color: var(--bs-danger);
+ border-radius: var(--bs-border-radius);
+}
+
+.was-validated :invalid ~ .invalid-feedback,
+.was-validated :invalid ~ .invalid-tooltip,
+.is-invalid ~ .invalid-feedback,
+.is-invalid ~ .invalid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:invalid, .form-control.is-invalid {
+ border-color: var(--bs-form-invalid-border-color);
+ padding-right: calc(1.5em + 1rem);
+ 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='%23da292e'%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='%23da292e' stroke='none'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right calc(0.375em + 0.25rem) center;
+ background-size: calc(0.75em + 0.5rem) calc(0.75em + 0.5rem);
+}
+.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {
+ border-color: var(--bs-form-invalid-border-color);
+ box-shadow: 0 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.5em + 1rem);
+ background-position: top calc(0.375em + 0.25rem) right calc(0.375em + 0.25rem);
+}
+
+.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='%23da292e'%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='%23da292e' stroke='none'/%3e%3c/svg%3e");
+ padding-right: 5.5rem;
+ background-position: right 1rem center, center right 3rem;
+ background-size: 16px 12px, calc(0.75em + 0.5rem) calc(0.75em + 0.5rem);
+}
+.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {
+ border-color: var(--bs-form-invalid-border-color);
+ box-shadow: 0 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.5em + 1rem));
+}
+
+.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 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: 0.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: 1rem;
+ --bs-btn-padding-y: 0.5rem;
+ --bs-btn-font-family: ;
+ --bs-btn-font-size: 0.875rem;
+ --bs-btn-font-weight: 500;
+ --bs-btn-line-height: 1.5;
+ --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: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-opacity: 0.65;
+ --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);
+ display: inline-block;
+ padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x);
+ font-family: var(--bs-btn-font-family);
+ font-size: var(--bs-btn-font-size);
+ font-weight: var(--bs-btn-font-weight);
+ line-height: var(--bs-btn-line-height);
+ color: var(--bs-btn-color);
+ text-align: center;
+ 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);
+ border-radius: var(--bs-btn-border-radius);
+ background-color: var(--bs-btn-bg);
+ box-shadow: var(--bs-btn-box-shadow);
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .btn {
+ transition: none;
+ }
+}
+.btn:hover {
+ color: var(--bs-btn-hover-color);
+ 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-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-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);
+ box-shadow: var(--bs-btn-active-shadow);
+}
+.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible {
+ box-shadow: var(--bs-btn-active-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);
+ box-shadow: none;
+}
+
+.btn-primary {
+ --bs-btn-color: #fff;
+ --bs-btn-bg: #3459e6;
+ --bs-btn-border-color: #3459e6;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #2c4cc4;
+ --bs-btn-hover-border-color: #2a47b8;
+ --bs-btn-focus-shadow-rgb: 82, 114, 234;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #2a47b8;
+ --bs-btn-active-border-color: #2743ad;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #3459e6;
+ --bs-btn-disabled-border-color: #3459e6;
+}
+
+.btn-secondary {
+ --bs-btn-color: #000;
+ --bs-btn-bg: #fff;
+ --bs-btn-border-color: #fff;
+ --bs-btn-hover-color: #000;
+ --bs-btn-hover-bg: white;
+ --bs-btn-hover-border-color: white;
+ --bs-btn-focus-shadow-rgb: 217, 217, 217;
+ --bs-btn-active-color: #000;
+ --bs-btn-active-bg: white;
+ --bs-btn-active-border-color: white;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #000;
+ --bs-btn-disabled-bg: #fff;
+ --bs-btn-disabled-border-color: #fff;
+}
+
+.btn-success {
+ --bs-btn-color: #fff;
+ --bs-btn-bg: #2fb380;
+ --bs-btn-border-color: #2fb380;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #28986d;
+ --bs-btn-hover-border-color: #268f66;
+ --bs-btn-focus-shadow-rgb: 78, 190, 147;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #268f66;
+ --bs-btn-active-border-color: #238660;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #2fb380;
+ --bs-btn-disabled-border-color: #2fb380;
+}
+
+.btn-info {
+ --bs-btn-color: #fff;
+ --bs-btn-bg: #287bb5;
+ --bs-btn-border-color: #287bb5;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #22699a;
+ --bs-btn-hover-border-color: #206291;
+ --bs-btn-focus-shadow-rgb: 72, 143, 192;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #206291;
+ --bs-btn-active-border-color: #1e5c88;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #287bb5;
+ --bs-btn-disabled-border-color: #287bb5;
+}
+
+.btn-warning {
+ --bs-btn-color: #fff;
+ --bs-btn-bg: #f4bd61;
+ --bs-btn-border-color: #f4bd61;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #cfa152;
+ --bs-btn-hover-border-color: #c3974e;
+ --bs-btn-focus-shadow-rgb: 246, 199, 121;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #c3974e;
+ --bs-btn-active-border-color: #b78e49;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #f4bd61;
+ --bs-btn-disabled-border-color: #f4bd61;
+}
+
+.btn-danger {
+ --bs-btn-color: #fff;
+ --bs-btn-bg: #da292e;
+ --bs-btn-border-color: #da292e;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #b92327;
+ --bs-btn-hover-border-color: #ae2125;
+ --bs-btn-focus-shadow-rgb: 224, 73, 77;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #ae2125;
+ --bs-btn-active-border-color: #a41f23;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #da292e;
+ --bs-btn-disabled-border-color: #da292e;
+}
+
+.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: #fff;
+ --bs-btn-active-bg: #c6c7c8;
+ --bs-btn-active-border-color: #babbbc;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --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: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: #212529;
+ --bs-btn-disabled-border-color: #212529;
+}
+
+.btn-outline-primary {
+ --bs-btn-color: #3459e6;
+ --bs-btn-border-color: #3459e6;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #3459e6;
+ --bs-btn-hover-border-color: #3459e6;
+ --bs-btn-focus-shadow-rgb: 52, 89, 230;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #3459e6;
+ --bs-btn-active-border-color: #3459e6;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #3459e6;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #3459e6;
+ --bs-gradient: none;
+}
+
+.btn-outline-secondary {
+ --bs-btn-color: #fff;
+ --bs-btn-border-color: #fff;
+ --bs-btn-hover-color: #000;
+ --bs-btn-hover-bg: #fff;
+ --bs-btn-hover-border-color: #fff;
+ --bs-btn-focus-shadow-rgb: 255, 255, 255;
+ --bs-btn-active-color: #000;
+ --bs-btn-active-bg: #fff;
+ --bs-btn-active-border-color: #fff;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #fff;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #fff;
+ --bs-gradient: none;
+}
+
+.btn-outline-success {
+ --bs-btn-color: #2fb380;
+ --bs-btn-border-color: #2fb380;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #2fb380;
+ --bs-btn-hover-border-color: #2fb380;
+ --bs-btn-focus-shadow-rgb: 47, 179, 128;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #2fb380;
+ --bs-btn-active-border-color: #2fb380;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #2fb380;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #2fb380;
+ --bs-gradient: none;
+}
+
+.btn-outline-info {
+ --bs-btn-color: #287bb5;
+ --bs-btn-border-color: #287bb5;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #287bb5;
+ --bs-btn-hover-border-color: #287bb5;
+ --bs-btn-focus-shadow-rgb: 40, 123, 181;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #287bb5;
+ --bs-btn-active-border-color: #287bb5;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #287bb5;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #287bb5;
+ --bs-gradient: none;
+}
+
+.btn-outline-warning {
+ --bs-btn-color: #f4bd61;
+ --bs-btn-border-color: #f4bd61;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #f4bd61;
+ --bs-btn-hover-border-color: #f4bd61;
+ --bs-btn-focus-shadow-rgb: 244, 189, 97;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #f4bd61;
+ --bs-btn-active-border-color: #f4bd61;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #f4bd61;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #f4bd61;
+ --bs-gradient: none;
+}
+
+.btn-outline-danger {
+ --bs-btn-color: #da292e;
+ --bs-btn-border-color: #da292e;
+ --bs-btn-hover-color: #fff;
+ --bs-btn-hover-bg: #da292e;
+ --bs-btn-hover-border-color: #da292e;
+ --bs-btn-focus-shadow-rgb: 218, 41, 46;
+ --bs-btn-active-color: #fff;
+ --bs-btn-active-bg: #da292e;
+ --bs-btn-active-border-color: #da292e;
+ --bs-btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-btn-disabled-color: #da292e;
+ --bs-btn-disabled-bg: transparent;
+ --bs-btn-disabled-border-color: #da292e;
+ --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: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --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: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --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: 82, 114, 234;
+ 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: 1.25rem;
+ --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.875rem;
+ --bs-btn-border-radius: var(--bs-border-radius-sm);
+}
+
+.fade {
+ transition: opacity 0.15s linear;
+}
+@media (prefers-reduced-motion: reduce) {
+ .fade {
+ transition: none;
+ }
+}
+.fade:not(.show) {
+ opacity: 0;
+}
+
+.collapse:not(.show) {
+ display: none;
+}
+
+.collapsing {
+ height: 0;
+ overflow: hidden;
+ transition: height 0.35s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .collapsing {
+ transition: none;
+ }
+}
+.collapsing.collapse-horizontal {
+ width: 0;
+ height: auto;
+ transition: width 0.35s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .collapsing.collapse-horizontal {
+ transition: none;
+ }
+}
+
+.dropup,
+.dropend,
+.dropdown,
+.dropstart,
+.dropup-center,
+.dropdown-center {
+ position: relative;
+}
+
+.dropdown-toggle {
+ white-space: nowrap;
+}
+.dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0;
+ border-left: 0.3em solid transparent;
+}
+.dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropdown-menu {
+ --bs-dropdown-zindex: 1000;
+ --bs-dropdown-min-width: 10rem;
+ --bs-dropdown-padding-x: 0;
+ --bs-dropdown-padding-y: 0.5rem;
+ --bs-dropdown-spacer: 0.125rem;
+ --bs-dropdown-font-size: 0.875rem;
+ --bs-dropdown-color: var(--bs-body-color);
+ --bs-dropdown-bg: var(--bs-body-bg);
+ --bs-dropdown-border-color: #dee2e6;
+ --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: #e9ecef;
+ --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: #fff;
+ --bs-dropdown-link-hover-bg: #3459e6;
+ --bs-dropdown-link-active-color: #fff;
+ --bs-dropdown-link-active-bg: #3459e6;
+ --bs-dropdown-link-disabled-color: var(--bs-tertiary-color);
+ --bs-dropdown-item-padding-x: 1rem;
+ --bs-dropdown-item-padding-y: 0.5rem;
+ --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);
+ border-radius: var(--bs-dropdown-border-radius);
+ box-shadow: var(--bs-dropdown-box-shadow);
+}
+.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: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0.3em solid;
+ border-left: 0.3em solid transparent;
+}
+.dropup .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropend .dropdown-menu[data-bs-popper] {
+ top: 0;
+ right: auto;
+ left: 100%;
+ margin-top: 0;
+ margin-left: var(--bs-dropdown-spacer);
+}
+.dropend .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0;
+ border-bottom: 0.3em solid transparent;
+ border-left: 0.3em solid;
+}
+.dropend .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+.dropend .dropdown-toggle::after {
+ vertical-align: 0;
+}
+
+.dropstart .dropdown-menu[data-bs-popper] {
+ top: 0;
+ right: 100%;
+ left: auto;
+ margin-top: 0;
+ margin-right: var(--bs-dropdown-spacer);
+}
+.dropstart .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+}
+.dropstart .dropdown-toggle::after {
+ display: none;
+}
+.dropstart .dropdown-toggle::before {
+ display: inline-block;
+ margin-right: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0.3em solid;
+ border-bottom: 0.3em solid transparent;
+}
+.dropstart .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+.dropstart .dropdown-toggle::before {
+ vertical-align: 0;
+}
+
+.dropdown-divider {
+ height: 0;
+ margin: var(--bs-dropdown-divider-margin-y) 0;
+ overflow: hidden;
+ border-top: 1px solid var(--bs-dropdown-divider-bg);
+ opacity: 1;
+}
+
+.dropdown-item {
+ display: block;
+ width: 100%;
+ padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);
+ clear: both;
+ font-weight: 400;
+ color: var(--bs-dropdown-link-color);
+ text-align: inherit;
+ text-decoration: none;
+ white-space: nowrap;
+ background-color: transparent;
+ border: 0;
+ border-radius: var(--bs-dropdown-item-border-radius, 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: transparent;
+}
+
+.dropdown-menu.show {
+ display: block;
+}
+
+.dropdown-header {
+ display: block;
+ padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);
+ margin-bottom: 0;
+ font-size: 0.875rem;
+ color: var(--bs-dropdown-header-color);
+ white-space: nowrap;
+}
+
+.dropdown-item-text {
+ display: block;
+ padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);
+ color: var(--bs-dropdown-link-color);
+}
+
+.dropdown-menu-dark {
+ --bs-dropdown-color: #dee2e6;
+ --bs-dropdown-bg: #343a40;
+ --bs-dropdown-border-color: #dee2e6;
+ --bs-dropdown-box-shadow: ;
+ --bs-dropdown-link-color: #dee2e6;
+ --bs-dropdown-link-hover-color: #fff;
+ --bs-dropdown-divider-bg: #e9ecef;
+ --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);
+ --bs-dropdown-link-active-color: #fff;
+ --bs-dropdown-link-active-bg: #3459e6;
+ --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 {
+ border-radius: var(--bs-border-radius);
+}
+.btn-group > :not(.btn-check:first-child) + .btn,
+.btn-group > .btn-group:not(:first-child) {
+ margin-left: calc(var(--bs-border-width) * -1);
+}
+.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group > .btn.dropdown-toggle-split:first-child,
+.btn-group > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn:nth-child(n+3),
+.btn-group > :not(.btn-check) + .btn,
+.btn-group > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.dropdown-toggle-split {
+ padding-right: 0.75rem;
+ padding-left: 0.75rem;
+}
+.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {
+ margin-left: 0;
+}
+.dropstart .dropdown-toggle-split::before {
+ margin-right: 0;
+}
+
+.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
+ padding-right: 0.375rem;
+ padding-left: 0.375rem;
+}
+
+.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
+ padding-right: 0.75rem;
+ padding-left: 0.75rem;
+}
+
+.btn-group.show .dropdown-toggle {
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.btn-group.show .dropdown-toggle.btn-link {
+ box-shadow: none;
+}
+
+.btn-group-vertical {
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group {
+ width: 100%;
+}
+.btn-group-vertical > .btn:not(:first-child),
+.btn-group-vertical > .btn-group:not(:first-child) {
+ margin-top: calc(var(--bs-border-width) * -1);
+}
+.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group-vertical > .btn-group:not(:last-child) > .btn {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn ~ .btn,
+.btn-group-vertical > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.nav {
+ --bs-nav-link-padding-x: 1rem;
+ --bs-nav-link-padding-y: 0.5rem;
+ --bs-nav-link-font-weight: ;
+ --bs-nav-link-color: #495057;
+ --bs-nav-link-hover-color: #495057;
+ --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;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .nav-link {
+ transition: none;
+ }
+}
+.nav-link:hover, .nav-link:focus {
+ color: var(--bs-nav-link-hover-color);
+}
+.nav-link:focus-visible {
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(52, 89, 230, 0.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: 0;
+ --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: #3459e6;
+ --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 transparent;
+ border-top-left-radius: var(--bs-nav-tabs-border-radius);
+ border-top-right-radius: var(--bs-nav-tabs-border-radius);
+}
+.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
+ isolation: isolate;
+ border-color: var(--bs-nav-tabs-link-hover-border-color);
+}
+.nav-tabs .nav-link.active,
+.nav-tabs .nav-item.show .nav-link {
+ color: var(--bs-nav-tabs-link-active-color);
+ background-color: var(--bs-nav-tabs-link-active-bg);
+ border-color: var(--bs-nav-tabs-link-active-border-color);
+}
+.nav-tabs .dropdown-menu {
+ margin-top: calc(-1 * var(--bs-nav-tabs-border-width));
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.nav-pills {
+ --bs-nav-pills-border-radius: var(--bs-border-radius);
+ --bs-nav-pills-link-active-color: #fff;
+ --bs-nav-pills-link-active-bg: #3459e6;
+}
+.nav-pills .nav-link {
+ border-radius: var(--bs-nav-pills-border-radius);
+}
+.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 transparent;
+}
+.nav-underline .nav-link:hover, .nav-underline .nav-link:focus {
+ border-bottom-color: currentcolor;
+}
+.nav-underline .nav-link.active,
+.nav-underline .show > .nav-link {
+ font-weight: 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.85rem;
+ --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.3125rem;
+ --bs-navbar-brand-margin-end: 1rem;
+ --bs-navbar-brand-font-size: 1.25rem;
+ --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.75rem;
+ --bs-navbar-toggler-padding-y: 0.25rem;
+ --bs-navbar-toggler-padding-x: 0.75rem;
+ --bs-navbar-toggler-font-size: 1.25rem;
+ --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2873, 80, 87, 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: 0.5rem;
+ padding-bottom: 0.5rem;
+ color: var(--bs-navbar-color);
+}
+.navbar-text a,
+.navbar-text a:hover,
+.navbar-text a:focus {
+ color: var(--bs-navbar-active-color);
+}
+
+.navbar-collapse {
+ flex-basis: 100%;
+ flex-grow: 1;
+ align-items: center;
+}
+
+.navbar-toggler {
+ padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);
+ font-size: var(--bs-navbar-toggler-font-size);
+ line-height: 1;
+ color: var(--bs-navbar-color);
+ background-color: transparent;
+ border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);
+ border-radius: var(--bs-navbar-toggler-border-radius);
+ transition: var(--bs-navbar-toggler-transition);
+}
+@media (prefers-reduced-motion: reduce) {
+ .navbar-toggler {
+ transition: none;
+ }
+}
+.navbar-toggler:hover {
+ text-decoration: none;
+}
+.navbar-toggler:focus {
+ text-decoration: none;
+ outline: 0;
+ box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width);
+}
+
+.navbar-toggler-icon {
+ display: inline-block;
+ width: 1.5em;
+ height: 1.5em;
+ vertical-align: middle;
+ background-image: var(--bs-navbar-toggler-icon-bg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 100%;
+}
+
+.navbar-nav-scroll {
+ max-height: var(--bs-scroll-height, 75vh);
+ overflow-y: auto;
+}
+
+@media (min-width: 576px) {
+ .navbar-expand-sm {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-sm .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-sm .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-sm .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+ }
+ .navbar-expand-sm .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-sm .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-sm .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-sm .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+ }
+ .navbar-expand-sm .offcanvas .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-sm .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-expand-md {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-md .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-md .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-md .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+ }
+ .navbar-expand-md .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-md .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-md .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-md .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+ }
+ .navbar-expand-md .offcanvas .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-md .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 992px) {
+ .navbar-expand-lg {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-lg .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-lg .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-lg .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+ }
+ .navbar-expand-lg .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-lg .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-lg .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-lg .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+ }
+ .navbar-expand-lg .offcanvas .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-lg .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 1200px) {
+ .navbar-expand-xl {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-xl .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-xl .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-xl .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+ }
+ .navbar-expand-xl .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-xl .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-xl .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-xl .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+ }
+ .navbar-expand-xl .offcanvas .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-xl .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 1400px) {
+ .navbar-expand-xxl {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-xxl .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-xxl .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-xxl .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+ }
+ .navbar-expand-xxl .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-xxl .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-xxl .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-xxl .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+ }
+ .navbar-expand-xxl .offcanvas .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-xxl .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+.navbar-expand {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+}
+.navbar-expand .navbar-nav {
+ flex-direction: row;
+}
+.navbar-expand .navbar-nav .dropdown-menu {
+ position: absolute;
+}
+.navbar-expand .navbar-nav .nav-link {
+ padding-right: var(--bs-navbar-nav-link-padding-x);
+ padding-left: var(--bs-navbar-nav-link-padding-x);
+}
+.navbar-expand .navbar-nav-scroll {
+ overflow: visible;
+}
+.navbar-expand .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+}
+.navbar-expand .navbar-toggler {
+ display: none;
+}
+.navbar-expand .offcanvas {
+ position: static;
+ z-index: auto;
+ flex-grow: 1;
+ width: auto !important;
+ height: auto !important;
+ visibility: visible !important;
+ background-color: transparent !important;
+ border: 0 !important;
+ transform: none !important;
+ box-shadow: none;
+ transition: none;
+}
+.navbar-expand .offcanvas .offcanvas-header {
+ display: none;
+}
+.navbar-expand .offcanvas .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+}
+
+.navbar-dark,
+.navbar[data-bs-theme=dark] {
+ --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: 1.5rem;
+ --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: 1rem;
+ --bs-card-cap-padding-x: 1.5rem;
+ --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);
+ border-radius: var(--bs-card-border-radius);
+ box-shadow: var(--bs-card-box-shadow);
+}
+.card > hr {
+ margin-right: 0;
+ margin-left: 0;
+}
+.card > .list-group {
+ border-top: inherit;
+ border-bottom: inherit;
+}
+.card > .list-group:first-child {
+ border-top-width: 0;
+ border-top-left-radius: var(--bs-card-inner-border-radius);
+ border-top-right-radius: var(--bs-card-inner-border-radius);
+}
+.card > .list-group:last-child {
+ border-bottom-width: 0;
+ border-bottom-right-radius: var(--bs-card-inner-border-radius);
+ border-bottom-left-radius: var(--bs-card-inner-border-radius);
+}
+.card > .card-header + .list-group,
+.card > .list-group + .card-footer {
+ border-top: 0;
+}
+
+.card-body {
+ flex: 1 1 auto;
+ padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x);
+ color: var(--bs-card-color);
+}
+
+.card-title {
+ margin-bottom: var(--bs-card-title-spacer-y);
+ 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-header:first-child {
+ border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0;
+}
+
+.card-footer {
+ padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);
+ color: var(--bs-card-cap-color);
+ background-color: var(--bs-card-cap-bg);
+ border-top: var(--bs-card-border-width) solid var(--bs-card-border-color);
+}
+.card-footer:last-child {
+ border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius);
+}
+
+.card-header-tabs {
+ margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));
+ margin-bottom: calc(-1 * var(--bs-card-cap-padding-y));
+ margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));
+ border-bottom: 0;
+}
+.card-header-tabs .nav-link.active {
+ background-color: var(--bs-card-bg);
+ border-bottom-color: var(--bs-card-bg);
+}
+
+.card-header-pills {
+ margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));
+ margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));
+}
+
+.card-img-overlay {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: var(--bs-card-img-overlay-padding);
+ border-radius: var(--bs-card-inner-border-radius);
+}
+
+.card-img,
+.card-img-top,
+.card-img-bottom {
+ width: 100%;
+}
+
+.card-img,
+.card-img-top {
+ border-top-left-radius: var(--bs-card-inner-border-radius);
+ border-top-right-radius: var(--bs-card-inner-border-radius);
+}
+
+.card-img,
+.card-img-bottom {
+ border-bottom-right-radius: var(--bs-card-inner-border-radius);
+ border-bottom-left-radius: var(--bs-card-inner-border-radius);
+}
+
+.card-group > .card {
+ margin-bottom: var(--bs-card-group-margin);
+}
+@media (min-width: 576px) {
+ .card-group {
+ display: flex;
+ flex-flow: row wrap;
+ }
+ .card-group > .card {
+ flex: 1 0 0%;
+ margin-bottom: 0;
+ }
+ .card-group > .card + .card {
+ margin-left: 0;
+ border-left: 0;
+ }
+ .card-group > .card:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-top,
+ .card-group > .card:not(:last-child) .card-header {
+ border-top-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-bottom,
+ .card-group > .card:not(:last-child) .card-footer {
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-top,
+ .card-group > .card:not(:first-child) .card-header {
+ border-top-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-bottom,
+ .card-group > .card:not(:first-child) .card-footer {
+ border-bottom-left-radius: 0;
+ }
+}
+
+.accordion {
+ --bs-accordion-color: var(--bs-body-color);
+ --bs-accordion-bg: var(--bs-body-bg);
+ --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: var(--bs-border-width);
+ --bs-accordion-border-radius: var(--bs-border-radius);
+ --bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));
+ --bs-accordion-btn-padding-x: 1.25rem;
+ --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='%23495057'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ --bs-accordion-btn-icon-width: 1.25rem;
+ --bs-accordion-btn-icon-transform: rotate(-180deg);
+ --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;
+ --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2315245c'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ --bs-accordion-btn-focus-border-color: #9aacf3;
+ --bs-accordion-btn-focus-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --bs-accordion-body-padding-x: 1.25rem;
+ --bs-accordion-body-padding-y: 1rem;
+ --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: 1rem;
+ color: var(--bs-accordion-btn-color);
+ text-align: left;
+ background-color: var(--bs-accordion-btn-bg);
+ border: 0;
+ border-radius: 0;
+ overflow-anchor: none;
+ transition: var(--bs-accordion-transition);
+}
+@media (prefers-reduced-motion: reduce) {
+ .accordion-button {
+ transition: none;
+ }
+}
+.accordion-button:not(.collapsed) {
+ color: var(--bs-accordion-active-color);
+ background-color: var(--bs-accordion-active-bg);
+ box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color);
+}
+.accordion-button:not(.collapsed)::after {
+ background-image: var(--bs-accordion-btn-active-icon);
+ transform: var(--bs-accordion-btn-icon-transform);
+}
+.accordion-button::after {
+ flex-shrink: 0;
+ width: var(--bs-accordion-btn-icon-width);
+ height: var(--bs-accordion-btn-icon-width);
+ margin-left: auto;
+ content: "";
+ background-image: var(--bs-accordion-btn-icon);
+ background-repeat: no-repeat;
+ background-size: var(--bs-accordion-btn-icon-width);
+ transition: var(--bs-accordion-btn-icon-transition);
+}
+@media (prefers-reduced-motion: reduce) {
+ .accordion-button::after {
+ transition: none;
+ }
+}
+.accordion-button:hover {
+ z-index: 2;
+}
+.accordion-button:focus {
+ z-index: 3;
+ border-color: var(--bs-accordion-btn-focus-border-color);
+ outline: 0;
+ box-shadow: var(--bs-accordion-btn-focus-box-shadow);
+}
+
+.accordion-header {
+ margin-bottom: 0;
+}
+
+.accordion-item {
+ color: var(--bs-accordion-color);
+ background-color: var(--bs-accordion-bg);
+ border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color);
+}
+.accordion-item:first-of-type {
+ border-top-left-radius: var(--bs-accordion-border-radius);
+ border-top-right-radius: var(--bs-accordion-border-radius);
+}
+.accordion-item:first-of-type .accordion-button {
+ border-top-left-radius: var(--bs-accordion-inner-border-radius);
+ border-top-right-radius: var(--bs-accordion-inner-border-radius);
+}
+.accordion-item:not(:first-of-type) {
+ border-top: 0;
+}
+.accordion-item:last-of-type {
+ border-bottom-right-radius: var(--bs-accordion-border-radius);
+ border-bottom-left-radius: var(--bs-accordion-border-radius);
+}
+.accordion-item:last-of-type .accordion-button.collapsed {
+ border-bottom-right-radius: var(--bs-accordion-inner-border-radius);
+ border-bottom-left-radius: var(--bs-accordion-inner-border-radius);
+}
+.accordion-item:last-of-type .accordion-collapse {
+ border-bottom-right-radius: var(--bs-accordion-border-radius);
+ border-bottom-left-radius: var(--bs-accordion-border-radius);
+}
+
+.accordion-body {
+ padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x);
+}
+
+.accordion-flush .accordion-collapse {
+ border-width: 0;
+}
+.accordion-flush .accordion-item {
+ border-right: 0;
+ border-left: 0;
+ border-radius: 0;
+}
+.accordion-flush .accordion-item:first-child {
+ border-top: 0;
+}
+.accordion-flush .accordion-item:last-child {
+ border-bottom: 0;
+}
+.accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed {
+ border-radius: 0;
+}
+
+[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='%23859bf0'%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='%23859bf0'%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: 1rem;
+ --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);
+ border-radius: var(--bs-breadcrumb-border-radius);
+}
+
+.breadcrumb-item + .breadcrumb-item {
+ padding-left: var(--bs-breadcrumb-item-padding-x);
+}
+.breadcrumb-item + .breadcrumb-item::before {
+ float: left;
+ padding-right: var(--bs-breadcrumb-item-padding-x);
+ color: var(--bs-breadcrumb-divider-color);
+ content: var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */;
+}
+.breadcrumb-item.active {
+ color: var(--bs-breadcrumb-item-active-color);
+}
+
+.pagination {
+ --bs-pagination-padding-x: 1rem;
+ --bs-pagination-padding-y: 0.5rem;
+ --bs-pagination-font-size: 1rem;
+ --bs-pagination-color: var(--bs-primary-bg);
+ --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-primary-bg);
+ --bs-pagination-hover-bg: var(--bs-secondary-bg);
+ --bs-pagination-hover-border-color: var(--bs-border-color);
+ --bs-pagination-focus-color: var(--bs-primary-bg);
+ --bs-pagination-focus-bg: var(--bs-secondary-bg);
+ --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(52, 89, 230, 0.25);
+ --bs-pagination-active-color: #fff;
+ --bs-pagination-active-bg: #3459e6;
+ --bs-pagination-active-border-color: #3459e6;
+ --bs-pagination-disabled-color: var(--bs-tertiary-color);
+ --bs-pagination-disabled-bg: var(--bs-tertiary-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);
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .page-link {
+ transition: none;
+ }
+}
+.page-link:hover {
+ z-index: 2;
+ color: 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);
+}
+.page-item:first-child .page-link {
+ border-top-left-radius: var(--bs-pagination-border-radius);
+ border-bottom-left-radius: var(--bs-pagination-border-radius);
+}
+.page-item:last-child .page-link {
+ border-top-right-radius: var(--bs-pagination-border-radius);
+ border-bottom-right-radius: var(--bs-pagination-border-radius);
+}
+
+.pagination-lg {
+ --bs-pagination-padding-x: 1.5rem;
+ --bs-pagination-padding-y: 0.75rem;
+ --bs-pagination-font-size: 1.25rem;
+ --bs-pagination-border-radius: var(--bs-border-radius-lg);
+}
+
+.pagination-sm {
+ --bs-pagination-padding-x: 0.5rem;
+ --bs-pagination-padding-y: 0.25rem;
+ --bs-pagination-font-size: 0.875rem;
+ --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;
+ border-radius: var(--bs-badge-border-radius);
+}
+.badge:empty {
+ display: none;
+}
+
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+
+.alert {
+ --bs-alert-bg: transparent;
+ --bs-alert-padding-x: 1rem;
+ --bs-alert-padding-y: 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);
+ border-radius: var(--bs-alert-border-radius);
+}
+
+.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);
+}
+
+@keyframes progress-bar-stripes {
+ 0% {
+ background-position-x: 1rem;
+ }
+}
+.progress,
+.progress-stacked {
+ --bs-progress-height: 1rem;
+ --bs-progress-font-size: 0.75rem;
+ --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: #3459e6;
+ --bs-progress-bar-transition: width 0.6s ease;
+ display: flex;
+ height: var(--bs-progress-height);
+ overflow: hidden;
+ font-size: var(--bs-progress-font-size);
+ background-color: var(--bs-progress-bg);
+ border-radius: var(--bs-progress-border-radius);
+ box-shadow: var(--bs-progress-box-shadow);
+}
+
+.progress-bar {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ overflow: hidden;
+ color: var(--bs-progress-bar-color);
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--bs-progress-bar-bg);
+ transition: var(--bs-progress-bar-transition);
+}
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar {
+ transition: none;
+ }
+}
+
+.progress-bar-striped {
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-size: var(--bs-progress-height) var(--bs-progress-height);
+}
+
+.progress-stacked > .progress {
+ overflow: visible;
+}
+
+.progress-stacked > .progress > .progress-bar {
+ width: 100%;
+}
+
+.progress-bar-animated {
+ animation: 1s linear infinite progress-bar-stripes;
+}
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar-animated {
+ animation: none;
+ }
+}
+
+.list-group {
+ --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: 1.5rem;
+ --bs-list-group-item-padding-y: 1rem;
+ --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: #3459e6;
+ --bs-list-group-active-border-color: #3459e6;
+ display: flex;
+ flex-direction: column;
+ padding-left: 0;
+ margin-bottom: 0;
+ border-radius: var(--bs-list-group-border-radius);
+}
+
+.list-group-numbered {
+ list-style-type: none;
+ counter-reset: section;
+}
+.list-group-numbered > .list-group-item::before {
+ content: counters(section, ".") ". ";
+ counter-increment: section;
+}
+
+.list-group-item-action {
+ width: 100%;
+ color: var(--bs-list-group-action-color);
+ text-align: inherit;
+}
+.list-group-item-action:hover, .list-group-item-action:focus {
+ z-index: 1;
+ color: var(--bs-list-group-action-hover-color);
+ text-decoration: none;
+ background-color: var(--bs-list-group-action-hover-bg);
+}
+.list-group-item-action:active {
+ color: var(--bs-list-group-action-active-color);
+ background-color: var(--bs-list-group-action-active-bg);
+}
+
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);
+ color: var(--bs-list-group-color);
+ 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:first-child {
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+.list-group-item:last-child {
+ border-bottom-right-radius: inherit;
+ border-bottom-left-radius: inherit;
+}
+.list-group-item.disabled, .list-group-item:disabled {
+ color: var(--bs-list-group-disabled-color);
+ pointer-events: none;
+ background-color: var(--bs-list-group-disabled-bg);
+}
+.list-group-item.active {
+ z-index: 2;
+ color: var(--bs-list-group-active-color);
+ background-color: var(--bs-list-group-active-bg);
+ border-color: var(--bs-list-group-active-border-color);
+}
+.list-group-item + .list-group-item {
+ border-top-width: 0;
+}
+.list-group-item + .list-group-item.active {
+ margin-top: calc(-1 * var(--bs-list-group-border-width));
+ border-top-width: var(--bs-list-group-border-width);
+}
+
+.list-group-horizontal {
+ flex-direction: row;
+}
+.list-group-horizontal > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+}
+.list-group-horizontal > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+}
+.list-group-horizontal > .list-group-item.active {
+ margin-top: 0;
+}
+.list-group-horizontal > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+}
+.list-group-horizontal > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+}
+
+@media (min-width: 576px) {
+ .list-group-horizontal-sm {
+ flex-direction: row;
+ }
+ .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+ }
+}
+@media (min-width: 768px) {
+ .list-group-horizontal-md {
+ flex-direction: row;
+ }
+ .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-md > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-md > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+ }
+ .list-group-horizontal-md > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+ }
+}
+@media (min-width: 992px) {
+ .list-group-horizontal-lg {
+ flex-direction: row;
+ }
+ .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+ }
+}
+@media (min-width: 1200px) {
+ .list-group-horizontal-xl {
+ flex-direction: row;
+ }
+ .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+ }
+}
+@media (min-width: 1400px) {
+ .list-group-horizontal-xxl {
+ flex-direction: row;
+ }
+ .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) {
+ border-bottom-left-radius: var(--bs-list-group-border-radius);
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) {
+ border-top-right-radius: var(--bs-list-group-border-radius);
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item + .list-group-item {
+ border-top-width: var(--bs-list-group-border-width);
+ border-left-width: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
+ border-left-width: var(--bs-list-group-border-width);
+ }
+}
+.list-group-flush {
+ border-radius: 0;
+}
+.list-group-flush > .list-group-item {
+ border-width: 0 0 var(--bs-list-group-border-width);
+}
+.list-group-flush > .list-group-item:last-child {
+ border-bottom-width: 0;
+}
+
+.list-group-item-primary {
+ --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(52, 89, 230, 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: 0.25em 0.25em;
+ color: var(--bs-btn-close-color);
+ background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;
+ border: 0;
+ border-radius: 0.375rem;
+ 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-primary-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);
+ border-radius: var(--bs-toast-border-radius);
+}
+.toast.showing {
+ opacity: 0;
+}
+.toast:not(.show) {
+ display: none;
+}
+
+.toast-container {
+ --bs-toast-zindex: 1090;
+ position: absolute;
+ z-index: var(--bs-toast-zindex);
+ width: -webkit-max-content;
+ width: -moz-max-content;
+ width: max-content;
+ max-width: 100%;
+ pointer-events: none;
+}
+.toast-container > :not(:last-child) {
+ margin-bottom: var(--bs-toast-spacing);
+}
+
+.toast-header {
+ display: flex;
+ align-items: center;
+ padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);
+ color: var(--bs-toast-header-color);
+ background-color: var(--bs-toast-header-bg);
+ background-clip: padding-box;
+ border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);
+ border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));
+ border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));
+}
+.toast-header .btn-close {
+ margin-right: calc(-0.5 * var(--bs-toast-padding-x));
+ margin-left: var(--bs-toast-padding-x);
+}
+
+.toast-body {
+ padding: var(--bs-toast-padding-x);
+ word-wrap: break-word;
+}
+
+.modal {
+ --bs-modal-zindex: 1055;
+ --bs-modal-width: 500px;
+ --bs-modal-padding: 1rem;
+ --bs-modal-margin: 0.5rem;
+ --bs-modal-color: ;
+ --bs-modal-bg: 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: 0;
+ --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: 0;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: var(--bs-modal-zindex);
+ display: none;
+ width: 100%;
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: auto;
+ outline: 0;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: var(--bs-modal-margin);
+ pointer-events: none;
+}
+.modal.fade .modal-dialog {
+ transition: transform 0.3s ease-out;
+ transform: translate(0, -50px);
+}
+@media (prefers-reduced-motion: reduce) {
+ .modal.fade .modal-dialog {
+ transition: none;
+ }
+}
+.modal.show .modal-dialog {
+ transform: none;
+}
+.modal.modal-static .modal-dialog {
+ transform: scale(1.02);
+}
+
+.modal-dialog-scrollable {
+ height: calc(100% - var(--bs-modal-margin) * 2);
+}
+.modal-dialog-scrollable .modal-content {
+ max-height: 100%;
+ overflow: hidden;
+}
+.modal-dialog-scrollable .modal-body {
+ overflow-y: auto;
+}
+
+.modal-dialog-centered {
+ display: flex;
+ align-items: center;
+ min-height: calc(100% - var(--bs-modal-margin) * 2);
+}
+
+.modal-content {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ color: var(--bs-modal-color);
+ pointer-events: auto;
+ background-color: var(--bs-modal-bg);
+ background-clip: padding-box;
+ border: var(--bs-modal-border-width) solid var(--bs-modal-border-color);
+ border-radius: var(--bs-modal-border-radius);
+ box-shadow: var(--bs-modal-box-shadow);
+ outline: 0;
+}
+
+.modal-backdrop {
+ --bs-backdrop-zindex: 1050;
+ --bs-backdrop-bg: #000;
+ --bs-backdrop-opacity: 0.5;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: var(--bs-backdrop-zindex);
+ width: 100vw;
+ height: 100vh;
+ background-color: var(--bs-backdrop-bg);
+}
+.modal-backdrop.fade {
+ opacity: 0;
+}
+.modal-backdrop.show {
+ opacity: var(--bs-backdrop-opacity);
+}
+
+.modal-header {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: space-between;
+ padding: var(--bs-modal-header-padding);
+ border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);
+ border-top-left-radius: var(--bs-modal-inner-border-radius);
+ border-top-right-radius: var(--bs-modal-inner-border-radius);
+}
+.modal-header .btn-close {
+ padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5);
+ margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto;
+}
+
+.modal-title {
+ margin-bottom: 0;
+ line-height: var(--bs-modal-title-line-height);
+}
+
+.modal-body {
+ position: relative;
+ flex: 1 1 auto;
+ padding: var(--bs-modal-padding);
+}
+
+.modal-footer {
+ display: flex;
+ flex-shrink: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: flex-end;
+ padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5);
+ background-color: var(--bs-modal-footer-bg);
+ border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);
+ border-bottom-right-radius: var(--bs-modal-inner-border-radius);
+ border-bottom-left-radius: var(--bs-modal-inner-border-radius);
+}
+.modal-footer > * {
+ margin: calc(var(--bs-modal-footer-gap) * 0.5);
+}
+
+@media (min-width: 576px) {
+ .modal {
+ --bs-modal-margin: 1.75rem;
+ --bs-modal-box-shadow: 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;
+ border-radius: 0;
+}
+.modal-fullscreen .modal-header,
+.modal-fullscreen .modal-footer {
+ border-radius: 0;
+}
+.modal-fullscreen .modal-body {
+ overflow-y: auto;
+}
+
+@media (max-width: 575.98px) {
+ .modal-fullscreen-sm-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-sm-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-sm-down .modal-header,
+ .modal-fullscreen-sm-down .modal-footer {
+ border-radius: 0;
+ }
+ .modal-fullscreen-sm-down .modal-body {
+ overflow-y: auto;
+ }
+}
+@media (max-width: 767.98px) {
+ .modal-fullscreen-md-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-md-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-md-down .modal-header,
+ .modal-fullscreen-md-down .modal-footer {
+ border-radius: 0;
+ }
+ .modal-fullscreen-md-down .modal-body {
+ overflow-y: auto;
+ }
+}
+@media (max-width: 991.98px) {
+ .modal-fullscreen-lg-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-lg-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-lg-down .modal-header,
+ .modal-fullscreen-lg-down .modal-footer {
+ border-radius: 0;
+ }
+ .modal-fullscreen-lg-down .modal-body {
+ overflow-y: auto;
+ }
+}
+@media (max-width: 1199.98px) {
+ .modal-fullscreen-xl-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-xl-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-xl-down .modal-header,
+ .modal-fullscreen-xl-down .modal-footer {
+ border-radius: 0;
+ }
+ .modal-fullscreen-xl-down .modal-body {
+ overflow-y: auto;
+ }
+}
+@media (max-width: 1399.98px) {
+ .modal-fullscreen-xxl-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-header,
+ .modal-fullscreen-xxl-down .modal-footer {
+ border-radius: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-body {
+ overflow-y: auto;
+ }
+}
+.tooltip {
+ --bs-tooltip-zindex: 1080;
+ --bs-tooltip-max-width: 200px;
+ --bs-tooltip-padding-x: 0.5rem;
+ --bs-tooltip-padding-y: 0.25rem;
+ --bs-tooltip-margin: ;
+ --bs-tooltip-font-size: 0.875rem;
+ --bs-tooltip-color: 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: transparent;
+ 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) * 0.5) 0;
+ border-top-color: var(--bs-tooltip-bg);
+}
+
+/* rtl:begin:ignore */
+.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {
+ left: 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) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0;
+ border-right-color: var(--bs-tooltip-bg);
+}
+
+/* rtl:end:ignore */
+.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {
+ top: 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) * 0.5) var(--bs-tooltip-arrow-height);
+ border-bottom-color: var(--bs-tooltip-bg);
+}
+
+/* rtl:begin:ignore */
+.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {
+ right: 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) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height);
+ border-left-color: var(--bs-tooltip-bg);
+}
+
+/* rtl:end:ignore */
+.tooltip-inner {
+ max-width: var(--bs-tooltip-max-width);
+ padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);
+ color: var(--bs-tooltip-color);
+ text-align: center;
+ background-color: var(--bs-tooltip-bg);
+ border-radius: var(--bs-tooltip-border-radius);
+}
+
+.popover {
+ --bs-popover-zindex: 1070;
+ --bs-popover-max-width: 276px;
+ --bs-popover-font-size: 0.875rem;
+ --bs-popover-bg: 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: 1rem;
+ --bs-popover-header-color: var(--bs-primary-color);
+ --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);
+ border-radius: var(--bs-popover-border-radius);
+ box-shadow: var(--bs-popover-box-shadow);
+}
+.popover .popover-arrow {
+ display: block;
+ width: var(--bs-popover-arrow-width);
+ height: var(--bs-popover-arrow-height);
+}
+.popover .popover-arrow::before, .popover .popover-arrow::after {
+ position: absolute;
+ display: block;
+ content: "";
+ border-color: transparent;
+ border-style: solid;
+ border-width: 0;
+}
+
+.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {
+ bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
+}
+.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {
+ border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;
+}
+.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before {
+ bottom: 0;
+ border-top-color: var(--bs-popover-arrow-border);
+}
+.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {
+ bottom: var(--bs-popover-border-width);
+ border-top-color: var(--bs-popover-bg);
+}
+
+/* rtl:begin:ignore */
+.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {
+ left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
+ width: var(--bs-popover-arrow-height);
+ height: var(--bs-popover-arrow-width);
+}
+.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {
+ border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;
+}
+.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before {
+ left: 0;
+ border-right-color: var(--bs-popover-arrow-border);
+}
+.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {
+ left: var(--bs-popover-border-width);
+ border-right-color: var(--bs-popover-bg);
+}
+
+/* rtl:end:ignore */
+.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {
+ top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
+}
+.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {
+ border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);
+}
+.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before {
+ top: 0;
+ border-bottom-color: var(--bs-popover-arrow-border);
+}
+.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {
+ top: var(--bs-popover-border-width);
+ border-bottom-color: var(--bs-popover-bg);
+}
+.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ display: block;
+ width: var(--bs-popover-arrow-width);
+ margin-left: calc(-0.5 * var(--bs-popover-arrow-width));
+ content: "";
+ border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg);
+}
+
+/* rtl:begin:ignore */
+.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {
+ right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
+ width: var(--bs-popover-arrow-height);
+ height: var(--bs-popover-arrow-width);
+}
+.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {
+ border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);
+}
+.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before {
+ right: 0;
+ border-left-color: var(--bs-popover-arrow-border);
+}
+.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {
+ right: var(--bs-popover-border-width);
+ border-left-color: var(--bs-popover-bg);
+}
+
+/* rtl:end:ignore */
+.popover-header {
+ padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);
+ margin-bottom: 0;
+ font-size: var(--bs-popover-header-font-size);
+ color: var(--bs-popover-header-color);
+ background-color: var(--bs-popover-header-bg);
+ border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color);
+ border-top-left-radius: var(--bs-popover-inner-border-radius);
+ border-top-right-radius: var(--bs-popover-inner-border-radius);
+}
+.popover-header:empty {
+ display: none;
+}
+
+.popover-body {
+ padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);
+ color: var(--bs-popover-body-color);
+}
+
+.carousel {
+ position: relative;
+}
+
+.carousel.pointer-event {
+ touch-action: pan-y;
+}
+
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.carousel-inner::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.carousel-item {
+ position: relative;
+ display: none;
+ float: left;
+ width: 100%;
+ margin-right: -100%;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ transition: transform 0.6s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-item {
+ transition: none;
+ }
+}
+
+.carousel-item.active,
+.carousel-item-next,
+.carousel-item-prev {
+ display: block;
+}
+
+.carousel-item-next:not(.carousel-item-start),
+.active.carousel-item-end {
+ transform: translateX(100%);
+}
+
+.carousel-item-prev:not(.carousel-item-end),
+.active.carousel-item-start {
+ transform: translateX(-100%);
+}
+
+.carousel-fade .carousel-item {
+ opacity: 0;
+ transition-property: opacity;
+ transform: none;
+}
+.carousel-fade .carousel-item.active,
+.carousel-fade .carousel-item-next.carousel-item-start,
+.carousel-fade .carousel-item-prev.carousel-item-end {
+ z-index: 1;
+ opacity: 1;
+}
+.carousel-fade .active.carousel-item-start,
+.carousel-fade .active.carousel-item-end {
+ z-index: 0;
+ opacity: 0;
+ transition: opacity 0s 0.6s;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-fade .active.carousel-item-start,
+ .carousel-fade .active.carousel-item-end {
+ transition: none;
+ }
+}
+
+.carousel-control-prev,
+.carousel-control-next {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 15%;
+ padding: 0;
+ color: #fff;
+ text-align: center;
+ background: none;
+ border: 0;
+ opacity: 0.5;
+ transition: opacity 0.15s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-control-prev,
+ .carousel-control-next {
+ transition: none;
+ }
+}
+.carousel-control-prev:hover, .carousel-control-prev:focus,
+.carousel-control-next:hover,
+.carousel-control-next:focus {
+ color: #fff;
+ text-decoration: none;
+ outline: 0;
+ opacity: 0.9;
+}
+
+.carousel-control-prev {
+ left: 0;
+}
+
+.carousel-control-next {
+ right: 0;
+}
+
+.carousel-control-prev-icon,
+.carousel-control-next-icon {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ background-repeat: no-repeat;
+ background-position: 50%;
+ background-size: 100% 100%;
+}
+
+/* rtl:options: {
+ "autoRename": true,
+ "stringMap":[ {
+ "name" : "prev-next",
+ "search" : "prev",
+ "replace" : "next"
+ } ]
+} */
+.carousel-control-prev-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e");
+}
+
+.carousel-control-next-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+}
+
+.carousel-indicators {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 2;
+ display: flex;
+ justify-content: center;
+ padding: 0;
+ margin-right: 15%;
+ margin-bottom: 1rem;
+ margin-left: 15%;
+}
+.carousel-indicators [data-bs-target] {
+ box-sizing: content-box;
+ flex: 0 1 auto;
+ width: 30px;
+ height: 3px;
+ padding: 0;
+ margin-right: 3px;
+ margin-left: 3px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 0;
+ border-top: 10px solid transparent;
+ border-bottom: 10px solid transparent;
+ opacity: 0.5;
+ transition: opacity 0.6s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-indicators [data-bs-target] {
+ transition: none;
+ }
+}
+.carousel-indicators .active {
+ opacity: 1;
+}
+
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 1.25rem;
+ left: 15%;
+ padding-top: 1.25rem;
+ padding-bottom: 1.25rem;
+ color: #fff;
+ text-align: center;
+}
+
+.carousel-dark .carousel-control-prev-icon,
+.carousel-dark .carousel-control-next-icon {
+ filter: invert(1) grayscale(100);
+}
+.carousel-dark .carousel-indicators [data-bs-target] {
+ background-color: #000;
+}
+.carousel-dark .carousel-caption {
+ color: #000;
+}
+
+[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: transparent;
+}
+
+.spinner-border-sm {
+ --bs-spinner-width: 1rem;
+ --bs-spinner-height: 1rem;
+ --bs-spinner-border-width: 0.2em;
+}
+
+@keyframes spinner-grow {
+ 0% {
+ transform: scale(0);
+ }
+ 50% {
+ opacity: 1;
+ transform: none;
+ }
+}
+.spinner-grow {
+ --bs-spinner-width: 2rem;
+ --bs-spinner-height: 2rem;
+ --bs-spinner-vertical-align: -0.125em;
+ --bs-spinner-animation-speed: 0.75s;
+ --bs-spinner-animation-name: spinner-grow;
+ background-color: currentcolor;
+ opacity: 0;
+}
+
+.spinner-grow-sm {
+ --bs-spinner-width: 1rem;
+ --bs-spinner-height: 1rem;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .spinner-border,
+ .spinner-grow {
+ --bs-spinner-animation-speed: 1.5s;
+ }
+}
+.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm {
+ --bs-offcanvas-zindex: 1045;
+ --bs-offcanvas-width: 400px;
+ --bs-offcanvas-height: 30vh;
+ --bs-offcanvas-padding-x: 1rem;
+ --bs-offcanvas-padding-y: 1rem;
+ --bs-offcanvas-color: 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;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+ }
+}
+@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) {
+ .offcanvas-sm {
+ transition: none;
+ }
+}
+@media (max-width: 575.98px) {
+ .offcanvas-sm.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--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: transparent !important;
+ }
+ .offcanvas-sm .offcanvas-header {
+ display: none;
+ }
+ .offcanvas-sm .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ background-color: transparent !important;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .offcanvas-md {
+ position: fixed;
+ bottom: 0;
+ z-index: var(--bs-offcanvas-zindex);
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ color: var(--bs-offcanvas-color);
+ visibility: hidden;
+ background-color: var(--bs-offcanvas-bg);
+ background-clip: padding-box;
+ outline: 0;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+ }
+}
+@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
+ .offcanvas-md {
+ transition: none;
+ }
+}
+@media (max-width: 767.98px) {
+ .offcanvas-md.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--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: transparent !important;
+ }
+ .offcanvas-md .offcanvas-header {
+ display: none;
+ }
+ .offcanvas-md .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ background-color: transparent !important;
+ }
+}
+
+@media (max-width: 991.98px) {
+ .offcanvas-lg {
+ position: fixed;
+ bottom: 0;
+ z-index: var(--bs-offcanvas-zindex);
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ color: var(--bs-offcanvas-color);
+ visibility: hidden;
+ background-color: var(--bs-offcanvas-bg);
+ background-clip: padding-box;
+ outline: 0;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+ }
+}
+@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
+ .offcanvas-lg {
+ transition: none;
+ }
+}
+@media (max-width: 991.98px) {
+ .offcanvas-lg.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--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: transparent !important;
+ }
+ .offcanvas-lg .offcanvas-header {
+ display: none;
+ }
+ .offcanvas-lg .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ background-color: transparent !important;
+ }
+}
+
+@media (max-width: 1199.98px) {
+ .offcanvas-xl {
+ position: fixed;
+ bottom: 0;
+ z-index: var(--bs-offcanvas-zindex);
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ color: var(--bs-offcanvas-color);
+ visibility: hidden;
+ background-color: var(--bs-offcanvas-bg);
+ background-clip: padding-box;
+ outline: 0;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+ }
+}
+@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) {
+ .offcanvas-xl {
+ transition: none;
+ }
+}
+@media (max-width: 1199.98px) {
+ .offcanvas-xl.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--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: transparent !important;
+ }
+ .offcanvas-xl .offcanvas-header {
+ display: none;
+ }
+ .offcanvas-xl .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ background-color: transparent !important;
+ }
+}
+
+@media (max-width: 1399.98px) {
+ .offcanvas-xxl {
+ position: fixed;
+ bottom: 0;
+ z-index: var(--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;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+ }
+}
+@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) {
+ .offcanvas-xxl {
+ transition: none;
+ }
+}
+@media (max-width: 1399.98px) {
+ .offcanvas-xxl.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--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: transparent !important;
+ }
+ .offcanvas-xxl .offcanvas-header {
+ display: none;
+ }
+ .offcanvas-xxl .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ background-color: transparent !important;
+ }
+}
+
+.offcanvas {
+ position: fixed;
+ bottom: 0;
+ z-index: var(--bs-offcanvas-zindex);
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ color: var(--bs-offcanvas-color);
+ visibility: hidden;
+ background-color: var(--bs-offcanvas-bg);
+ background-clip: padding-box;
+ outline: 0;
+ box-shadow: var(--bs-offcanvas-box-shadow);
+ transition: var(--bs-offcanvas-transition);
+}
+@media (prefers-reduced-motion: reduce) {
+ .offcanvas {
+ transition: none;
+ }
+}
+.offcanvas.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: var(--bs-offcanvas-width);
+ border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
+ transform: translateX(-100%);
+}
+.offcanvas.offcanvas-end {
+ top: 0;
+ right: 0;
+ width: var(--bs-offcanvas-width);
+ border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
+ transform: translateX(100%);
+}
+.offcanvas.offcanvas-top {
+ top: 0;
+ right: 0;
+ left: 0;
+ height: var(--bs-offcanvas-height);
+ max-height: 100%;
+ border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
+ transform: translateY(-100%);
+}
+.offcanvas.offcanvas-bottom {
+ right: 0;
+ left: 0;
+ height: var(--bs-offcanvas-height);
+ max-height: 100%;
+ border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);
+ transform: translateY(100%);
+}
+.offcanvas.showing, .offcanvas.show:not(.hiding) {
+ transform: none;
+}
+.offcanvas.showing, .offcanvas.hiding, .offcanvas.show {
+ visibility: visible;
+}
+
+.offcanvas-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1040;
+ width: 100vw;
+ height: 100vh;
+ background-color: #000;
+}
+.offcanvas-backdrop.fade {
+ opacity: 0;
+}
+.offcanvas-backdrop.show {
+ opacity: 0.5;
+}
+
+.offcanvas-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);
+}
+.offcanvas-header .btn-close {
+ padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5);
+ margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y));
+ margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x));
+ margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y));
+}
+
+.offcanvas-title {
+ margin-bottom: 0;
+ line-height: 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: 0.5;
+}
+.placeholder.btn::before {
+ display: inline-block;
+ content: "";
+}
+
+.placeholder-xs {
+ min-height: 0.6em;
+}
+
+.placeholder-sm {
+ min-height: 0.8em;
+}
+
+.placeholder-lg {
+ min-height: 1.2em;
+}
+
+.placeholder-glow .placeholder {
+ animation: placeholder-glow 2s ease-in-out infinite;
+}
+
+@keyframes placeholder-glow {
+ 50% {
+ opacity: 0.2;
+ }
+}
+.placeholder-wave {
+ -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);
+ mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);
+ -webkit-mask-size: 200% 100%;
+ mask-size: 200% 100%;
+ animation: placeholder-wave 2s linear infinite;
+}
+
+@keyframes placeholder-wave {
+ 100% {
+ -webkit-mask-position: -200% 0%;
+ mask-position: -200% 0%;
+ }
+}
+.clearfix::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.text-bg-primary {
+ color: #fff !important;
+ background-color: RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important;
+}
+
+.text-bg-secondary {
+ color: #000 !important;
+ background-color: RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important;
+}
+
+.text-bg-success {
+ color: #fff !important;
+ background-color: RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important;
+}
+
+.text-bg-info {
+ color: #fff !important;
+ background-color: RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important;
+}
+
+.text-bg-warning {
+ color: #fff !important;
+ background-color: RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important;
+}
+
+.text-bg-danger {
+ color: #fff !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;
+ -webkit-text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-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(42, 71, 184, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(42, 71, 184, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(42, 71, 184, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-secondary {
+ color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-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(255, 255, 255, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(255, 255, 255, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(255, 255, 255, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-success {
+ color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-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(38, 143, 102, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(38, 143, 102, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(38, 143, 102, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-info {
+ color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-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(32, 98, 145, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(32, 98, 145, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(32, 98, 145, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-warning {
+ color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-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(195, 151, 78, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(195, 151, 78, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(195, 151, 78, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-danger {
+ color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-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(174, 33, 37, var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(174, 33, 37, var(--bs-link-underline-opacity, 1)) !important;
+ text-decoration-color: RGBA(174, 33, 37, var(--bs-link-underline-opacity, 1)) !important;
+}
+
+.link-light {
+ color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;
+ -webkit-text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-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;
+ -webkit-text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-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;
+ -webkit-text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-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;
+ -webkit-text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-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;
+ -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-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;
+ -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-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: 0.375rem;
+ align-items: center;
+ -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));
+ text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));
+ text-underline-offset: 0.25em;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+}
+.icon-link > .bi {
+ flex-shrink: 0;
+ width: 1em;
+ height: 1em;
+ fill: currentcolor;
+ transition: 0.2s ease-in-out transform;
+}
+@media (prefers-reduced-motion: reduce) {
+ .icon-link > .bi {
+ transition: none;
+ }
+}
+
+.icon-link-hover:hover > .bi, .icon-link-hover:focus-visible > .bi {
+ transform: var(--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: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+}
+
+.sticky-bottom {
+ position: -webkit-sticky;
+ position: sticky;
+ bottom: 0;
+ z-index: 1020;
+}
+
+@media (min-width: 576px) {
+ .sticky-sm-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+ .sticky-sm-bottom {
+ position: -webkit-sticky;
+ position: sticky;
+ bottom: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 768px) {
+ .sticky-md-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+ .sticky-md-bottom {
+ position: -webkit-sticky;
+ position: sticky;
+ bottom: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 992px) {
+ .sticky-lg-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+ .sticky-lg-bottom {
+ position: -webkit-sticky;
+ position: sticky;
+ bottom: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 1200px) {
+ .sticky-xl-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+ .sticky-xl-bottom {
+ position: -webkit-sticky;
+ position: sticky;
+ bottom: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 1400px) {
+ .sticky-xxl-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+ .sticky-xxl-bottom {
+ position: -webkit-sticky;
+ 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: 0.25;
+}
+
+.align-baseline {
+ vertical-align: baseline !important;
+}
+
+.align-top {
+ vertical-align: top !important;
+}
+
+.align-middle {
+ vertical-align: middle !important;
+}
+
+.align-bottom {
+ vertical-align: bottom !important;
+}
+
+.align-text-bottom {
+ vertical-align: text-bottom !important;
+}
+
+.align-text-top {
+ vertical-align: text-top !important;
+}
+
+.float-start {
+ float: left !important;
+}
+
+.float-end {
+ float: right !important;
+}
+
+.float-none {
+ float: none !important;
+}
+
+.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: 0.25 !important;
+}
+
+.opacity-50 {
+ opacity: 0.5 !important;
+}
+
+.opacity-75 {
+ opacity: 0.75 !important;
+}
+
+.opacity-100 {
+ opacity: 1 !important;
+}
+
+.overflow-auto {
+ overflow: auto !important;
+}
+
+.overflow-hidden {
+ overflow: hidden !important;
+}
+
+.overflow-visible {
+ overflow: visible !important;
+}
+
+.overflow-scroll {
+ overflow: scroll !important;
+}
+
+.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: -webkit-sticky !important;
+ position: sticky !important;
+}
+
+.top-0 {
+ top: 0 !important;
+}
+
+.top-50 {
+ top: 50% !important;
+}
+
+.top-100 {
+ top: 100% !important;
+}
+
+.bottom-0 {
+ bottom: 0 !important;
+}
+
+.bottom-50 {
+ bottom: 50% !important;
+}
+
+.bottom-100 {
+ bottom: 100% !important;
+}
+
+.start-0 {
+ left: 0 !important;
+}
+
+.start-50 {
+ left: 50% !important;
+}
+
+.start-100 {
+ left: 100% !important;
+}
+
+.end-0 {
+ right: 0 !important;
+}
+
+.end-50 {
+ right: 50% !important;
+}
+
+.end-100 {
+ right: 100% !important;
+}
+
+.translate-middle {
+ transform: translate(-50%, -50%) !important;
+}
+
+.translate-middle-x {
+ transform: translateX(-50%) !important;
+}
+
+.translate-middle-y {
+ transform: translateY(-50%) !important;
+}
+
+.border {
+ border: 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: 0.25rem !important;
+}
+
+.m-2 {
+ margin: 0.5rem !important;
+}
+
+.m-3 {
+ margin: 1rem !important;
+}
+
+.m-4 {
+ margin: 1.5rem !important;
+}
+
+.m-5 {
+ margin: 3rem !important;
+}
+
+.m-auto {
+ margin: auto !important;
+}
+
+.mx-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+}
+
+.mx-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+}
+
+.mx-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+}
+
+.mx-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+}
+
+.mx-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+}
+
+.mx-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+}
+
+.mx-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+}
+
+.my-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+.my-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+}
+
+.my-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+}
+
+.my-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+}
+
+.my-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+}
+
+.my-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+}
+
+.my-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+}
+
+.mt-0 {
+ margin-top: 0 !important;
+}
+
+.mt-1 {
+ margin-top: 0.25rem !important;
+}
+
+.mt-2 {
+ margin-top: 0.5rem !important;
+}
+
+.mt-3 {
+ margin-top: 1rem !important;
+}
+
+.mt-4 {
+ margin-top: 1.5rem !important;
+}
+
+.mt-5 {
+ margin-top: 3rem !important;
+}
+
+.mt-auto {
+ margin-top: auto !important;
+}
+
+.me-0 {
+ margin-right: 0 !important;
+}
+
+.me-1 {
+ margin-right: 0.25rem !important;
+}
+
+.me-2 {
+ margin-right: 0.5rem !important;
+}
+
+.me-3 {
+ margin-right: 1rem !important;
+}
+
+.me-4 {
+ margin-right: 1.5rem !important;
+}
+
+.me-5 {
+ margin-right: 3rem !important;
+}
+
+.me-auto {
+ margin-right: auto !important;
+}
+
+.mb-0 {
+ margin-bottom: 0 !important;
+}
+
+.mb-1 {
+ margin-bottom: 0.25rem !important;
+}
+
+.mb-2 {
+ margin-bottom: 0.5rem !important;
+}
+
+.mb-3 {
+ margin-bottom: 1rem !important;
+}
+
+.mb-4 {
+ margin-bottom: 1.5rem !important;
+}
+
+.mb-5 {
+ margin-bottom: 3rem !important;
+}
+
+.mb-auto {
+ margin-bottom: auto !important;
+}
+
+.ms-0 {
+ margin-left: 0 !important;
+}
+
+.ms-1 {
+ margin-left: 0.25rem !important;
+}
+
+.ms-2 {
+ margin-left: 0.5rem !important;
+}
+
+.ms-3 {
+ margin-left: 1rem !important;
+}
+
+.ms-4 {
+ margin-left: 1.5rem !important;
+}
+
+.ms-5 {
+ margin-left: 3rem !important;
+}
+
+.ms-auto {
+ margin-left: auto !important;
+}
+
+.p-0 {
+ padding: 0 !important;
+}
+
+.p-1 {
+ padding: 0.25rem !important;
+}
+
+.p-2 {
+ padding: 0.5rem !important;
+}
+
+.p-3 {
+ padding: 1rem !important;
+}
+
+.p-4 {
+ padding: 1.5rem !important;
+}
+
+.p-5 {
+ padding: 3rem !important;
+}
+
+.px-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+}
+
+.px-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+}
+
+.px-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+}
+
+.px-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+}
+
+.px-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+}
+
+.px-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+}
+
+.py-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+}
+
+.py-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+}
+
+.py-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+}
+
+.py-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+}
+
+.py-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+}
+
+.py-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+}
+
+.pt-0 {
+ padding-top: 0 !important;
+}
+
+.pt-1 {
+ padding-top: 0.25rem !important;
+}
+
+.pt-2 {
+ padding-top: 0.5rem !important;
+}
+
+.pt-3 {
+ padding-top: 1rem !important;
+}
+
+.pt-4 {
+ padding-top: 1.5rem !important;
+}
+
+.pt-5 {
+ padding-top: 3rem !important;
+}
+
+.pe-0 {
+ padding-right: 0 !important;
+}
+
+.pe-1 {
+ padding-right: 0.25rem !important;
+}
+
+.pe-2 {
+ padding-right: 0.5rem !important;
+}
+
+.pe-3 {
+ padding-right: 1rem !important;
+}
+
+.pe-4 {
+ padding-right: 1.5rem !important;
+}
+
+.pe-5 {
+ padding-right: 3rem !important;
+}
+
+.pb-0 {
+ padding-bottom: 0 !important;
+}
+
+.pb-1 {
+ padding-bottom: 0.25rem !important;
+}
+
+.pb-2 {
+ padding-bottom: 0.5rem !important;
+}
+
+.pb-3 {
+ padding-bottom: 1rem !important;
+}
+
+.pb-4 {
+ padding-bottom: 1.5rem !important;
+}
+
+.pb-5 {
+ padding-bottom: 3rem !important;
+}
+
+.ps-0 {
+ padding-left: 0 !important;
+}
+
+.ps-1 {
+ padding-left: 0.25rem !important;
+}
+
+.ps-2 {
+ padding-left: 0.5rem !important;
+}
+
+.ps-3 {
+ padding-left: 1rem !important;
+}
+
+.ps-4 {
+ padding-left: 1.5rem !important;
+}
+
+.ps-5 {
+ padding-left: 3rem !important;
+}
+
+.gap-0 {
+ gap: 0 !important;
+}
+
+.gap-1 {
+ gap: 0.25rem !important;
+}
+
+.gap-2 {
+ gap: 0.5rem !important;
+}
+
+.gap-3 {
+ gap: 1rem !important;
+}
+
+.gap-4 {
+ gap: 1.5rem !important;
+}
+
+.gap-5 {
+ gap: 3rem !important;
+}
+
+.row-gap-0 {
+ row-gap: 0 !important;
+}
+
+.row-gap-1 {
+ row-gap: 0.25rem !important;
+}
+
+.row-gap-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+}
+
+.column-gap-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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.375rem + 1.5vw) !important;
+}
+
+.fs-2 {
+ font-size: calc(1.325rem + 0.9vw) !important;
+}
+
+.fs-3 {
+ font-size: calc(1.3rem + 0.6vw) !important;
+}
+
+.fs-4 {
+ font-size: calc(1.275rem + 0.3vw) !important;
+}
+
+.fs-5 {
+ font-size: 1.25rem !important;
+}
+
+.fs-6 {
+ font-size: 1rem !important;
+}
+
+.fst-italic {
+ font-style: italic !important;
+}
+
+.fst-normal {
+ font-style: normal !important;
+}
+
+.fw-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;
+}
+
+/* rtl:begin:remove */
+.text-break {
+ word-wrap: break-word !important;
+ word-break: break-word !important;
+}
+
+/* rtl:end:remove */
+.text-primary {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-secondary {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-success {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-info {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-warning {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-danger {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-light {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-dark {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-black {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-white {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-body {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-body-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, 0.5) !important;
+}
+
+.text-white-50 {
+ --bs-text-opacity: 1;
+ color: rgba(255, 255, 255, 0.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: 0.125em !important;
+}
+
+.link-offset-1-hover:hover {
+ text-underline-offset: 0.125em !important;
+}
+
+.link-offset-2 {
+ text-underline-offset: 0.25em !important;
+}
+
+.link-offset-2-hover:hover {
+ text-underline-offset: 0.25em !important;
+}
+
+.link-offset-3 {
+ text-underline-offset: 0.375em !important;
+}
+
+.link-offset-3-hover:hover {
+ text-underline-offset: 0.375em !important;
+}
+
+.link-underline-primary {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-secondary {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-success {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-info {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-warning {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-danger {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-light {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline-dark {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;
+ text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;
+}
+
+.link-underline {
+ --bs-link-underline-opacity: 1;
+ -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
+ 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: transparent !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: 0.25rem !important;
+ }
+ .m-sm-2 {
+ margin: 0.5rem !important;
+ }
+ .m-sm-3 {
+ margin: 1rem !important;
+ }
+ .m-sm-4 {
+ margin: 1.5rem !important;
+ }
+ .m-sm-5 {
+ margin: 3rem !important;
+ }
+ .m-sm-auto {
+ margin: auto !important;
+ }
+ .mx-sm-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+ .mx-sm-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+ .mx-sm-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+ .mx-sm-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+ .mx-sm-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+ .mx-sm-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+ .mx-sm-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+ .my-sm-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+ .my-sm-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+ .my-sm-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+ .my-sm-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+ .my-sm-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+ .my-sm-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+ .my-sm-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+ .mt-sm-0 {
+ margin-top: 0 !important;
+ }
+ .mt-sm-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mt-sm-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mt-sm-3 {
+ margin-top: 1rem !important;
+ }
+ .mt-sm-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mt-sm-5 {
+ margin-top: 3rem !important;
+ }
+ .mt-sm-auto {
+ margin-top: auto !important;
+ }
+ .me-sm-0 {
+ margin-right: 0 !important;
+ }
+ .me-sm-1 {
+ margin-right: 0.25rem !important;
+ }
+ .me-sm-2 {
+ margin-right: 0.5rem !important;
+ }
+ .me-sm-3 {
+ margin-right: 1rem !important;
+ }
+ .me-sm-4 {
+ margin-right: 1.5rem !important;
+ }
+ .me-sm-5 {
+ margin-right: 3rem !important;
+ }
+ .me-sm-auto {
+ margin-right: auto !important;
+ }
+ .mb-sm-0 {
+ margin-bottom: 0 !important;
+ }
+ .mb-sm-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .mb-sm-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .mb-sm-3 {
+ margin-bottom: 1rem !important;
+ }
+ .mb-sm-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .mb-sm-5 {
+ margin-bottom: 3rem !important;
+ }
+ .mb-sm-auto {
+ margin-bottom: auto !important;
+ }
+ .ms-sm-0 {
+ margin-left: 0 !important;
+ }
+ .ms-sm-1 {
+ margin-left: 0.25rem !important;
+ }
+ .ms-sm-2 {
+ margin-left: 0.5rem !important;
+ }
+ .ms-sm-3 {
+ margin-left: 1rem !important;
+ }
+ .ms-sm-4 {
+ margin-left: 1.5rem !important;
+ }
+ .ms-sm-5 {
+ margin-left: 3rem !important;
+ }
+ .ms-sm-auto {
+ margin-left: auto !important;
+ }
+ .p-sm-0 {
+ padding: 0 !important;
+ }
+ .p-sm-1 {
+ padding: 0.25rem !important;
+ }
+ .p-sm-2 {
+ padding: 0.5rem !important;
+ }
+ .p-sm-3 {
+ padding: 1rem !important;
+ }
+ .p-sm-4 {
+ padding: 1.5rem !important;
+ }
+ .p-sm-5 {
+ padding: 3rem !important;
+ }
+ .px-sm-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+ .px-sm-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+ .px-sm-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+ .px-sm-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+ .px-sm-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+ .px-sm-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+ .py-sm-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+ .py-sm-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+ .py-sm-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+ .py-sm-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+ .py-sm-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+ .py-sm-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+ .pt-sm-0 {
+ padding-top: 0 !important;
+ }
+ .pt-sm-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pt-sm-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pt-sm-3 {
+ padding-top: 1rem !important;
+ }
+ .pt-sm-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pt-sm-5 {
+ padding-top: 3rem !important;
+ }
+ .pe-sm-0 {
+ padding-right: 0 !important;
+ }
+ .pe-sm-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pe-sm-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pe-sm-3 {
+ padding-right: 1rem !important;
+ }
+ .pe-sm-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pe-sm-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-sm-0 {
+ padding-bottom: 0 !important;
+ }
+ .pb-sm-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pb-sm-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pb-sm-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pb-sm-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pb-sm-5 {
+ padding-bottom: 3rem !important;
+ }
+ .ps-sm-0 {
+ padding-left: 0 !important;
+ }
+ .ps-sm-1 {
+ padding-left: 0.25rem !important;
+ }
+ .ps-sm-2 {
+ padding-left: 0.5rem !important;
+ }
+ .ps-sm-3 {
+ padding-left: 1rem !important;
+ }
+ .ps-sm-4 {
+ padding-left: 1.5rem !important;
+ }
+ .ps-sm-5 {
+ padding-left: 3rem !important;
+ }
+ .gap-sm-0 {
+ gap: 0 !important;
+ }
+ .gap-sm-1 {
+ gap: 0.25rem !important;
+ }
+ .gap-sm-2 {
+ gap: 0.5rem !important;
+ }
+ .gap-sm-3 {
+ gap: 1rem !important;
+ }
+ .gap-sm-4 {
+ gap: 1.5rem !important;
+ }
+ .gap-sm-5 {
+ gap: 3rem !important;
+ }
+ .row-gap-sm-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-sm-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-sm-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-sm-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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: 0.25rem !important;
+ }
+ .m-md-2 {
+ margin: 0.5rem !important;
+ }
+ .m-md-3 {
+ margin: 1rem !important;
+ }
+ .m-md-4 {
+ margin: 1.5rem !important;
+ }
+ .m-md-5 {
+ margin: 3rem !important;
+ }
+ .m-md-auto {
+ margin: auto !important;
+ }
+ .mx-md-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+ .mx-md-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+ .mx-md-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+ .mx-md-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+ .mx-md-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+ .mx-md-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+ .mx-md-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+ .my-md-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+ .my-md-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+ .my-md-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+ .my-md-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+ .my-md-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+ .my-md-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+ .my-md-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+ .mt-md-0 {
+ margin-top: 0 !important;
+ }
+ .mt-md-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mt-md-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mt-md-3 {
+ margin-top: 1rem !important;
+ }
+ .mt-md-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mt-md-5 {
+ margin-top: 3rem !important;
+ }
+ .mt-md-auto {
+ margin-top: auto !important;
+ }
+ .me-md-0 {
+ margin-right: 0 !important;
+ }
+ .me-md-1 {
+ margin-right: 0.25rem !important;
+ }
+ .me-md-2 {
+ margin-right: 0.5rem !important;
+ }
+ .me-md-3 {
+ margin-right: 1rem !important;
+ }
+ .me-md-4 {
+ margin-right: 1.5rem !important;
+ }
+ .me-md-5 {
+ margin-right: 3rem !important;
+ }
+ .me-md-auto {
+ margin-right: auto !important;
+ }
+ .mb-md-0 {
+ margin-bottom: 0 !important;
+ }
+ .mb-md-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .mb-md-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .mb-md-3 {
+ margin-bottom: 1rem !important;
+ }
+ .mb-md-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .mb-md-5 {
+ margin-bottom: 3rem !important;
+ }
+ .mb-md-auto {
+ margin-bottom: auto !important;
+ }
+ .ms-md-0 {
+ margin-left: 0 !important;
+ }
+ .ms-md-1 {
+ margin-left: 0.25rem !important;
+ }
+ .ms-md-2 {
+ margin-left: 0.5rem !important;
+ }
+ .ms-md-3 {
+ margin-left: 1rem !important;
+ }
+ .ms-md-4 {
+ margin-left: 1.5rem !important;
+ }
+ .ms-md-5 {
+ margin-left: 3rem !important;
+ }
+ .ms-md-auto {
+ margin-left: auto !important;
+ }
+ .p-md-0 {
+ padding: 0 !important;
+ }
+ .p-md-1 {
+ padding: 0.25rem !important;
+ }
+ .p-md-2 {
+ padding: 0.5rem !important;
+ }
+ .p-md-3 {
+ padding: 1rem !important;
+ }
+ .p-md-4 {
+ padding: 1.5rem !important;
+ }
+ .p-md-5 {
+ padding: 3rem !important;
+ }
+ .px-md-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+ .px-md-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+ .px-md-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+ .px-md-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+ .px-md-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+ .px-md-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+ .py-md-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+ .py-md-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+ .py-md-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+ .py-md-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+ .py-md-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+ .py-md-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+ .pt-md-0 {
+ padding-top: 0 !important;
+ }
+ .pt-md-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pt-md-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pt-md-3 {
+ padding-top: 1rem !important;
+ }
+ .pt-md-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pt-md-5 {
+ padding-top: 3rem !important;
+ }
+ .pe-md-0 {
+ padding-right: 0 !important;
+ }
+ .pe-md-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pe-md-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pe-md-3 {
+ padding-right: 1rem !important;
+ }
+ .pe-md-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pe-md-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-md-0 {
+ padding-bottom: 0 !important;
+ }
+ .pb-md-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pb-md-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pb-md-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pb-md-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pb-md-5 {
+ padding-bottom: 3rem !important;
+ }
+ .ps-md-0 {
+ padding-left: 0 !important;
+ }
+ .ps-md-1 {
+ padding-left: 0.25rem !important;
+ }
+ .ps-md-2 {
+ padding-left: 0.5rem !important;
+ }
+ .ps-md-3 {
+ padding-left: 1rem !important;
+ }
+ .ps-md-4 {
+ padding-left: 1.5rem !important;
+ }
+ .ps-md-5 {
+ padding-left: 3rem !important;
+ }
+ .gap-md-0 {
+ gap: 0 !important;
+ }
+ .gap-md-1 {
+ gap: 0.25rem !important;
+ }
+ .gap-md-2 {
+ gap: 0.5rem !important;
+ }
+ .gap-md-3 {
+ gap: 1rem !important;
+ }
+ .gap-md-4 {
+ gap: 1.5rem !important;
+ }
+ .gap-md-5 {
+ gap: 3rem !important;
+ }
+ .row-gap-md-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-md-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-md-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-md-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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: 0.25rem !important;
+ }
+ .m-lg-2 {
+ margin: 0.5rem !important;
+ }
+ .m-lg-3 {
+ margin: 1rem !important;
+ }
+ .m-lg-4 {
+ margin: 1.5rem !important;
+ }
+ .m-lg-5 {
+ margin: 3rem !important;
+ }
+ .m-lg-auto {
+ margin: auto !important;
+ }
+ .mx-lg-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+ .mx-lg-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+ .mx-lg-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+ .mx-lg-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+ .mx-lg-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+ .mx-lg-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+ .mx-lg-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+ .my-lg-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+ .my-lg-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+ .my-lg-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+ .my-lg-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+ .my-lg-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+ .my-lg-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+ .my-lg-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+ .mt-lg-0 {
+ margin-top: 0 !important;
+ }
+ .mt-lg-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mt-lg-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mt-lg-3 {
+ margin-top: 1rem !important;
+ }
+ .mt-lg-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mt-lg-5 {
+ margin-top: 3rem !important;
+ }
+ .mt-lg-auto {
+ margin-top: auto !important;
+ }
+ .me-lg-0 {
+ margin-right: 0 !important;
+ }
+ .me-lg-1 {
+ margin-right: 0.25rem !important;
+ }
+ .me-lg-2 {
+ margin-right: 0.5rem !important;
+ }
+ .me-lg-3 {
+ margin-right: 1rem !important;
+ }
+ .me-lg-4 {
+ margin-right: 1.5rem !important;
+ }
+ .me-lg-5 {
+ margin-right: 3rem !important;
+ }
+ .me-lg-auto {
+ margin-right: auto !important;
+ }
+ .mb-lg-0 {
+ margin-bottom: 0 !important;
+ }
+ .mb-lg-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .mb-lg-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .mb-lg-3 {
+ margin-bottom: 1rem !important;
+ }
+ .mb-lg-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .mb-lg-5 {
+ margin-bottom: 3rem !important;
+ }
+ .mb-lg-auto {
+ margin-bottom: auto !important;
+ }
+ .ms-lg-0 {
+ margin-left: 0 !important;
+ }
+ .ms-lg-1 {
+ margin-left: 0.25rem !important;
+ }
+ .ms-lg-2 {
+ margin-left: 0.5rem !important;
+ }
+ .ms-lg-3 {
+ margin-left: 1rem !important;
+ }
+ .ms-lg-4 {
+ margin-left: 1.5rem !important;
+ }
+ .ms-lg-5 {
+ margin-left: 3rem !important;
+ }
+ .ms-lg-auto {
+ margin-left: auto !important;
+ }
+ .p-lg-0 {
+ padding: 0 !important;
+ }
+ .p-lg-1 {
+ padding: 0.25rem !important;
+ }
+ .p-lg-2 {
+ padding: 0.5rem !important;
+ }
+ .p-lg-3 {
+ padding: 1rem !important;
+ }
+ .p-lg-4 {
+ padding: 1.5rem !important;
+ }
+ .p-lg-5 {
+ padding: 3rem !important;
+ }
+ .px-lg-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+ .px-lg-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+ .px-lg-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+ .px-lg-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+ .px-lg-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+ .px-lg-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+ .py-lg-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+ .py-lg-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+ .py-lg-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+ .py-lg-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+ .py-lg-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+ .py-lg-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+ .pt-lg-0 {
+ padding-top: 0 !important;
+ }
+ .pt-lg-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pt-lg-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pt-lg-3 {
+ padding-top: 1rem !important;
+ }
+ .pt-lg-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pt-lg-5 {
+ padding-top: 3rem !important;
+ }
+ .pe-lg-0 {
+ padding-right: 0 !important;
+ }
+ .pe-lg-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pe-lg-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pe-lg-3 {
+ padding-right: 1rem !important;
+ }
+ .pe-lg-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pe-lg-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-lg-0 {
+ padding-bottom: 0 !important;
+ }
+ .pb-lg-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pb-lg-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pb-lg-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pb-lg-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pb-lg-5 {
+ padding-bottom: 3rem !important;
+ }
+ .ps-lg-0 {
+ padding-left: 0 !important;
+ }
+ .ps-lg-1 {
+ padding-left: 0.25rem !important;
+ }
+ .ps-lg-2 {
+ padding-left: 0.5rem !important;
+ }
+ .ps-lg-3 {
+ padding-left: 1rem !important;
+ }
+ .ps-lg-4 {
+ padding-left: 1.5rem !important;
+ }
+ .ps-lg-5 {
+ padding-left: 3rem !important;
+ }
+ .gap-lg-0 {
+ gap: 0 !important;
+ }
+ .gap-lg-1 {
+ gap: 0.25rem !important;
+ }
+ .gap-lg-2 {
+ gap: 0.5rem !important;
+ }
+ .gap-lg-3 {
+ gap: 1rem !important;
+ }
+ .gap-lg-4 {
+ gap: 1.5rem !important;
+ }
+ .gap-lg-5 {
+ gap: 3rem !important;
+ }
+ .row-gap-lg-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-lg-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-lg-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-lg-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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: 0.25rem !important;
+ }
+ .m-xl-2 {
+ margin: 0.5rem !important;
+ }
+ .m-xl-3 {
+ margin: 1rem !important;
+ }
+ .m-xl-4 {
+ margin: 1.5rem !important;
+ }
+ .m-xl-5 {
+ margin: 3rem !important;
+ }
+ .m-xl-auto {
+ margin: auto !important;
+ }
+ .mx-xl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+ .mx-xl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+ .mx-xl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+ .mx-xl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+ .mx-xl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+ .mx-xl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+ .mx-xl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+ .my-xl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+ .my-xl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+ .my-xl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+ .my-xl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+ .my-xl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+ .my-xl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+ .my-xl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+ .mt-xl-0 {
+ margin-top: 0 !important;
+ }
+ .mt-xl-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mt-xl-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mt-xl-3 {
+ margin-top: 1rem !important;
+ }
+ .mt-xl-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mt-xl-5 {
+ margin-top: 3rem !important;
+ }
+ .mt-xl-auto {
+ margin-top: auto !important;
+ }
+ .me-xl-0 {
+ margin-right: 0 !important;
+ }
+ .me-xl-1 {
+ margin-right: 0.25rem !important;
+ }
+ .me-xl-2 {
+ margin-right: 0.5rem !important;
+ }
+ .me-xl-3 {
+ margin-right: 1rem !important;
+ }
+ .me-xl-4 {
+ margin-right: 1.5rem !important;
+ }
+ .me-xl-5 {
+ margin-right: 3rem !important;
+ }
+ .me-xl-auto {
+ margin-right: auto !important;
+ }
+ .mb-xl-0 {
+ margin-bottom: 0 !important;
+ }
+ .mb-xl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .mb-xl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .mb-xl-3 {
+ margin-bottom: 1rem !important;
+ }
+ .mb-xl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .mb-xl-5 {
+ margin-bottom: 3rem !important;
+ }
+ .mb-xl-auto {
+ margin-bottom: auto !important;
+ }
+ .ms-xl-0 {
+ margin-left: 0 !important;
+ }
+ .ms-xl-1 {
+ margin-left: 0.25rem !important;
+ }
+ .ms-xl-2 {
+ margin-left: 0.5rem !important;
+ }
+ .ms-xl-3 {
+ margin-left: 1rem !important;
+ }
+ .ms-xl-4 {
+ margin-left: 1.5rem !important;
+ }
+ .ms-xl-5 {
+ margin-left: 3rem !important;
+ }
+ .ms-xl-auto {
+ margin-left: auto !important;
+ }
+ .p-xl-0 {
+ padding: 0 !important;
+ }
+ .p-xl-1 {
+ padding: 0.25rem !important;
+ }
+ .p-xl-2 {
+ padding: 0.5rem !important;
+ }
+ .p-xl-3 {
+ padding: 1rem !important;
+ }
+ .p-xl-4 {
+ padding: 1.5rem !important;
+ }
+ .p-xl-5 {
+ padding: 3rem !important;
+ }
+ .px-xl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+ .px-xl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+ .px-xl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+ .px-xl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+ .px-xl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+ .px-xl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+ .py-xl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+ .py-xl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+ .py-xl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+ .py-xl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+ .py-xl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+ .py-xl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+ .pt-xl-0 {
+ padding-top: 0 !important;
+ }
+ .pt-xl-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pt-xl-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pt-xl-3 {
+ padding-top: 1rem !important;
+ }
+ .pt-xl-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pt-xl-5 {
+ padding-top: 3rem !important;
+ }
+ .pe-xl-0 {
+ padding-right: 0 !important;
+ }
+ .pe-xl-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pe-xl-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pe-xl-3 {
+ padding-right: 1rem !important;
+ }
+ .pe-xl-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pe-xl-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-xl-0 {
+ padding-bottom: 0 !important;
+ }
+ .pb-xl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pb-xl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pb-xl-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pb-xl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pb-xl-5 {
+ padding-bottom: 3rem !important;
+ }
+ .ps-xl-0 {
+ padding-left: 0 !important;
+ }
+ .ps-xl-1 {
+ padding-left: 0.25rem !important;
+ }
+ .ps-xl-2 {
+ padding-left: 0.5rem !important;
+ }
+ .ps-xl-3 {
+ padding-left: 1rem !important;
+ }
+ .ps-xl-4 {
+ padding-left: 1.5rem !important;
+ }
+ .ps-xl-5 {
+ padding-left: 3rem !important;
+ }
+ .gap-xl-0 {
+ gap: 0 !important;
+ }
+ .gap-xl-1 {
+ gap: 0.25rem !important;
+ }
+ .gap-xl-2 {
+ gap: 0.5rem !important;
+ }
+ .gap-xl-3 {
+ gap: 1rem !important;
+ }
+ .gap-xl-4 {
+ gap: 1.5rem !important;
+ }
+ .gap-xl-5 {
+ gap: 3rem !important;
+ }
+ .row-gap-xl-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-xl-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-xl-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-xl-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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: 0.25rem !important;
+ }
+ .m-xxl-2 {
+ margin: 0.5rem !important;
+ }
+ .m-xxl-3 {
+ margin: 1rem !important;
+ }
+ .m-xxl-4 {
+ margin: 1.5rem !important;
+ }
+ .m-xxl-5 {
+ margin: 3rem !important;
+ }
+ .m-xxl-auto {
+ margin: auto !important;
+ }
+ .mx-xxl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+ .mx-xxl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+ .mx-xxl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+ .mx-xxl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+ .mx-xxl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+ .mx-xxl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+ .mx-xxl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+ .my-xxl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+ .my-xxl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+ .my-xxl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+ .my-xxl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+ .my-xxl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+ .my-xxl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+ .my-xxl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+ .mt-xxl-0 {
+ margin-top: 0 !important;
+ }
+ .mt-xxl-1 {
+ margin-top: 0.25rem !important;
+ }
+ .mt-xxl-2 {
+ margin-top: 0.5rem !important;
+ }
+ .mt-xxl-3 {
+ margin-top: 1rem !important;
+ }
+ .mt-xxl-4 {
+ margin-top: 1.5rem !important;
+ }
+ .mt-xxl-5 {
+ margin-top: 3rem !important;
+ }
+ .mt-xxl-auto {
+ margin-top: auto !important;
+ }
+ .me-xxl-0 {
+ margin-right: 0 !important;
+ }
+ .me-xxl-1 {
+ margin-right: 0.25rem !important;
+ }
+ .me-xxl-2 {
+ margin-right: 0.5rem !important;
+ }
+ .me-xxl-3 {
+ margin-right: 1rem !important;
+ }
+ .me-xxl-4 {
+ margin-right: 1.5rem !important;
+ }
+ .me-xxl-5 {
+ margin-right: 3rem !important;
+ }
+ .me-xxl-auto {
+ margin-right: auto !important;
+ }
+ .mb-xxl-0 {
+ margin-bottom: 0 !important;
+ }
+ .mb-xxl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+ .mb-xxl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+ .mb-xxl-3 {
+ margin-bottom: 1rem !important;
+ }
+ .mb-xxl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+ .mb-xxl-5 {
+ margin-bottom: 3rem !important;
+ }
+ .mb-xxl-auto {
+ margin-bottom: auto !important;
+ }
+ .ms-xxl-0 {
+ margin-left: 0 !important;
+ }
+ .ms-xxl-1 {
+ margin-left: 0.25rem !important;
+ }
+ .ms-xxl-2 {
+ margin-left: 0.5rem !important;
+ }
+ .ms-xxl-3 {
+ margin-left: 1rem !important;
+ }
+ .ms-xxl-4 {
+ margin-left: 1.5rem !important;
+ }
+ .ms-xxl-5 {
+ margin-left: 3rem !important;
+ }
+ .ms-xxl-auto {
+ margin-left: auto !important;
+ }
+ .p-xxl-0 {
+ padding: 0 !important;
+ }
+ .p-xxl-1 {
+ padding: 0.25rem !important;
+ }
+ .p-xxl-2 {
+ padding: 0.5rem !important;
+ }
+ .p-xxl-3 {
+ padding: 1rem !important;
+ }
+ .p-xxl-4 {
+ padding: 1.5rem !important;
+ }
+ .p-xxl-5 {
+ padding: 3rem !important;
+ }
+ .px-xxl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+ .px-xxl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+ .px-xxl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+ .px-xxl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+ .px-xxl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+ .px-xxl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+ .py-xxl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+ .py-xxl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+ .py-xxl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+ .py-xxl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+ .py-xxl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+ .py-xxl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+ .pt-xxl-0 {
+ padding-top: 0 !important;
+ }
+ .pt-xxl-1 {
+ padding-top: 0.25rem !important;
+ }
+ .pt-xxl-2 {
+ padding-top: 0.5rem !important;
+ }
+ .pt-xxl-3 {
+ padding-top: 1rem !important;
+ }
+ .pt-xxl-4 {
+ padding-top: 1.5rem !important;
+ }
+ .pt-xxl-5 {
+ padding-top: 3rem !important;
+ }
+ .pe-xxl-0 {
+ padding-right: 0 !important;
+ }
+ .pe-xxl-1 {
+ padding-right: 0.25rem !important;
+ }
+ .pe-xxl-2 {
+ padding-right: 0.5rem !important;
+ }
+ .pe-xxl-3 {
+ padding-right: 1rem !important;
+ }
+ .pe-xxl-4 {
+ padding-right: 1.5rem !important;
+ }
+ .pe-xxl-5 {
+ padding-right: 3rem !important;
+ }
+ .pb-xxl-0 {
+ padding-bottom: 0 !important;
+ }
+ .pb-xxl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+ .pb-xxl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+ .pb-xxl-3 {
+ padding-bottom: 1rem !important;
+ }
+ .pb-xxl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+ .pb-xxl-5 {
+ padding-bottom: 3rem !important;
+ }
+ .ps-xxl-0 {
+ padding-left: 0 !important;
+ }
+ .ps-xxl-1 {
+ padding-left: 0.25rem !important;
+ }
+ .ps-xxl-2 {
+ padding-left: 0.5rem !important;
+ }
+ .ps-xxl-3 {
+ padding-left: 1rem !important;
+ }
+ .ps-xxl-4 {
+ padding-left: 1.5rem !important;
+ }
+ .ps-xxl-5 {
+ padding-left: 3rem !important;
+ }
+ .gap-xxl-0 {
+ gap: 0 !important;
+ }
+ .gap-xxl-1 {
+ gap: 0.25rem !important;
+ }
+ .gap-xxl-2 {
+ gap: 0.5rem !important;
+ }
+ .gap-xxl-3 {
+ gap: 1rem !important;
+ }
+ .gap-xxl-4 {
+ gap: 1.5rem !important;
+ }
+ .gap-xxl-5 {
+ gap: 3rem !important;
+ }
+ .row-gap-xxl-0 {
+ row-gap: 0 !important;
+ }
+ .row-gap-xxl-1 {
+ row-gap: 0.25rem !important;
+ }
+ .row-gap-xxl-2 {
+ row-gap: 0.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: 0.25rem !important;
+ column-gap: 0.25rem !important;
+ }
+ .column-gap-xxl-2 {
+ -moz-column-gap: 0.5rem !important;
+ column-gap: 0.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.5rem !important;
+ }
+ .fs-2 {
+ font-size: 2rem !important;
+ }
+ .fs-3 {
+ font-size: 1.75rem !important;
+ }
+ .fs-4 {
+ font-size: 1.5rem !important;
+ }
+}
+@media print {
+ .d-print-inline {
+ display: inline !important;
+ }
+ .d-print-inline-block {
+ display: inline-block !important;
+ }
+ .d-print-block {
+ display: block !important;
+ }
+ .d-print-grid {
+ display: grid !important;
+ }
+ .d-print-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;
+ }
+}
+.navbar {
+ font-size: 0.875rem;
+ font-weight: 500;
+}
+.navbar .nav-item {
+ margin-right: 0.5rem;
+ margin-left: 0.5rem;
+}
+.navbar .navbar-nav .nav-link {
+ border-radius: 0.375rem;
+}
+
+.navbar-dark .navbar-nav .nav-link:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+.navbar-dark .navbar-nav .nav-link.active {
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+.navbar-light .navbar-nav .nav-link:hover {
+ background-color: rgba(0, 0, 0, 0.03);
+}
+.navbar-light .navbar-nav .nav-link.active {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+
+.navbar-nav {
+ --bs-nav-link-padding-x: .5rem;
+}
+
+.btn-secondary,
+.btn-light,
+.btn-outline-secondary,
+.btn-outline-light {
+ color: #212529;
+}
+.btn-secondary:disabled, .btn-secondary.disabled,
+.btn-light:disabled,
+.btn-light.disabled,
+.btn-outline-secondary:disabled,
+.btn-outline-secondary.disabled,
+.btn-outline-light:disabled,
+.btn-outline-light.disabled {
+ border: 1px solid #e6e6e6;
+}
+
+.btn-secondary,
+.btn-outline-secondary {
+ border-color: #e6e6e6;
+}
+.btn-secondary:hover, .btn-secondary:active,
+.btn-outline-secondary:hover,
+.btn-outline-secondary:active {
+ background-color: #e6e6e6;
+ border-color: #e6e6e6;
+}
+
+.btn-light,
+.btn-outline-light {
+ border-color: #dfe0e1;
+}
+.btn-light:hover, .btn-light:active,
+.btn-outline-light:hover,
+.btn-outline-light:active {
+ background-color: #dfe0e1;
+ border-color: #dfe0e1;
+}
+
+.table {
+ font-size: 0.875rem;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+}
+
+thead th {
+ font-size: 0.875rem;
+ text-transform: uppercase;
+}
+
+.input-group-text {
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.nav-tabs {
+ font-weight: 500;
+}
+.nav-tabs .nav-link {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+ border-width: 0 0 1px;
+}
+.nav-tabs .nav-link.active,
+.nav-tabs .nav-item.show .nav-link {
+ box-shadow: inset 0 -2px 0 #3459e6;
+}
+
+.nav-pills {
+ font-weight: 500;
+}
+
+.pagination {
+ font-size: 0.875rem;
+ font-weight: 500;
+}
+.pagination .page-link {
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.breadcrumb {
+ font-size: 0.875rem;
+ font-weight: 500;
+ border: 1px solid var(--bs-secondary-bg);
+ border-radius: 0.375rem;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.breadcrumb-item {
+ padding: 1rem 0.5rem 1rem 0;
+}
+
+.breadcrumb-item + .breadcrumb-item::before {
+ padding-right: 1rem;
+}
+
+.alert .btn-close {
+ color: inherit;
+}
+
+.badge.bg-secondary, .badge.bg-light {
+ color: #212529;
+}
+
+.list-group-item h1,
+.list-group-item h2,
+.list-group-item h3,
+.list-group-item h4,
+.list-group-item h5,
+.list-group-item h6,
+.list-group-item .h1,
+.list-group-item .h2,
+.list-group-item .h3,
+.list-group-item .h4,
+.list-group-item .h5,
+.list-group-item .h6,
+.card h1,
+.card h2,
+.card h3,
+.card h4,
+.card h5,
+.card h6,
+.card .h1,
+.card .h2,
+.card .h3,
+.card .h4,
+.card .h5,
+.card .h6 {
+ color: inherit;
+}
+
+.list-group {
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+}
+
+.card {
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+}
+
+.modal-footer {
+ background-color: var(--bs-tertiary-bg);
+}
+
+.modal-content {
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+}
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/styles/fonts.css b/VisualPinball.Unity/Documentation~/template/vpe/styles/fonts.css
deleted file mode 100644
index 2ee636e79..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/styles/fonts.css
+++ /dev/null
@@ -1,208 +0,0 @@
-
-
-
-/*
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-Thin.woff2?v=3.15") format("woff2"),
- url("Inter-Thin.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 100;
- font-display: swap;
- src: url("Inter-ThinItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ThinItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLight.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraLight.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 200;
- font-display: swap;
- src: url("Inter-ExtraLightItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraLightItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-Light.woff2?v=3.15") format("woff2"),
- url("Inter-Light.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 300;
- font-display: swap;
- src: url("Inter-LightItalic.woff2?v=3.15") format("woff2"),
- url("Inter-LightItalic.woff?v=3.15") format("woff");
-}
-*/
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 400;
- font-display: swap;
- src: url("/fonts/Inter-Regular.woff2?v=3.15") format("woff2"),
- url("/fonts/Inter-Regular.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url("/fonts/Inter-Italic.woff2?v=3.15") format("woff2"),
- url("/fonts/Inter-Italic.woff?v=3.15") format("woff");
-}
-/*
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-Medium.woff2?v=3.15") format("woff2"),
- url("Inter-Medium.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 500;
- font-display: swap;
- src: url("Inter-MediumItalic.woff2?v=3.15") format("woff2"),
- url("Inter-MediumItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBold.woff2?v=3.15") format("woff2"),
- url("Inter-SemiBold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 600;
- font-display: swap;
- src: url("Inter-SemiBoldItalic.woff2?v=3.15") format("woff2"),
- url("Inter-SemiBoldItalic.woff?v=3.15") format("woff");
-}
-*/
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url("/fonts/Inter-Bold.woff2?v=3.15") format("woff2"),
- url("/fonts/Inter-Bold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url("/fonts/Inter-BoldItalic.woff2?v=3.15") format("woff2"),
- url("/fonts/Inter-BoldItalic.woff?v=3.15") format("woff");
-}
-/*
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBold.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraBold.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 800;
- font-display: swap;
- src: url("Inter-ExtraBoldItalic.woff2?v=3.15") format("woff2"),
- url("Inter-ExtraBoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-Black.woff2?v=3.15") format("woff2"),
- url("Inter-Black.woff?v=3.15") format("woff");
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 900;
- font-display: swap;
- src: url("Inter-BlackItalic.woff2?v=3.15") format("woff2"),
- url("Inter-BlackItalic.woff?v=3.15") format("woff");
-}
-*/
-/* -------------------------------------------------------
-Variable font.
-Usage:
-
- html { font-family: 'Inter', sans-serif; }
- @supports (font-variation-settings: normal) {
- html { font-family: 'Inter var', sans-serif; }
- }
-*/
-
-/*
-@font-face {
- font-family: 'Inter var';
- font-weight: 100 900;
- font-display: swap;
- font-style: normal;
- font-named-instance: 'Regular';
- src: url("Inter-roman.var.woff2?v=3.15") format("woff2");
-}
-@font-face {
- font-family: 'Inter var';
- font-weight: 100 900;
- font-display: swap;
- font-style: italic;
- font-named-instance: 'Italic';
- src: url("Inter-italic.var.woff2?v=3.15") format("woff2");
-}
-*/
-
-/* --------------------------------------------------------------------------
-[EXPERIMENTAL] Multi-axis, single variable font.
-
-Slant axis is not yet widely supported (as of February 2019) and thus this
-multi-axis single variable font is opt-in rather than the default.
-
-When using this, you will probably need to set font-variation-settings
-explicitly, e.g.
-
- * { font-variation-settings: "slnt" 0deg }
- .italic { font-variation-settings: "slnt" 10deg }
-
-*/
-/*
-@font-face {
- font-family: 'Inter var experimental';
- font-weight: 100 900;
- font-display: swap;
- font-style: oblique 0deg 10deg;
- src: url("Inter.var.woff2?v=3.15") format("woff2");
-}
-*/
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/styles/main.css b/VisualPinball.Unity/Documentation~/template/vpe/styles/main.css
deleted file mode 100644
index cc0a74e32..000000000
--- a/VisualPinball.Unity/Documentation~/template/vpe/styles/main.css
+++ /dev/null
@@ -1,56 +0,0 @@
-html,
-body {
- font-family: Inter, 'Segoe UI', Tahoma, Helvetica, sans-serif;
- font-size: 100%;
-
-}
-
-.btn.btn-default.active, .btn.btn-default:active {
- outline: 0;
- -webkit-box-shadow: none;
- box-shadow: none;
- background-color: rgba(1,1,1,0.08);
-}
-
-.navbar-brand > svg {
- margin-top: 6px;
-}
-
-.navbar-github > svg {
- margin-top: 8px;
- fill: #ccc;
-}
-
-.navbar-default {
- background-color: rgba(1,1,1,0.05);
- border-color: rgba(1,1,1,0.1);
-}
-
-#sidetoc .sidefilter {
- top: 94px;
-}
-
-#sidetoc .sidetoc.shiftup {
- bottom: 0;
-}
-
-img[alt="Visual Pinball Engine"] {
- margin-top: 15px;
-}
-
-h1, h2 {
- font-weight: bold;
-}
-
-.table-bordered,
-.table-bordered>tbody>tr>td,
-.table-bordered>tbody>tr>th,
-.table-bordered>tfoot>tr>td,
-.table-bordered>tfoot>tr>th,
-.table-bordered>thead>tr>td,
-.table-bordered>thead>tr>th {
- border-color: rgba(1,1,1,0.15);
-}
-.table-striped > tbody > tr:nth-of-type(odd) {
- background-color: rgba(1,1,1,0.03)
-}
\ No newline at end of file
diff --git a/VisualPinball.Unity/Documentation~/template/vpe/token.json b/VisualPinball.Unity/Documentation~/template/vpe/token.json
new file mode 100644
index 000000000..203df6dd8
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/template/vpe/token.json
@@ -0,0 +1,4 @@
+{
+ "improveThisDoc": "Improve this Page",
+ "inThisArticle": "Table of Contents"
+}
diff --git a/VisualPinball.Unity/Documentation~/toc.yml b/VisualPinball.Unity/Documentation~/toc.yml
index bdab2402d..20d6500f4 100644
--- a/VisualPinball.Unity/Documentation~/toc.yml
+++ b/VisualPinball.Unity/Documentation~/toc.yml
@@ -2,8 +2,5 @@
href: creators-guide/
- name: Plugins
href: plugins/
-- name: API Documentation
- href: api/
- homepage: api/index.md
- name: Changelog
href: /CHANGELOG.html
diff --git a/VisualPinball.Unity/Documentation~/vpe.svg b/VisualPinball.Unity/Documentation~/vpe.svg
deleted file mode 100644
index c47ac3a0a..000000000
--- a/VisualPinball.Unity/Documentation~/vpe.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TableSelectorHook.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TableSelectorHook.cs
index f04d0e46b..f921e7fd9 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TableSelectorHook.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TableSelectorHook.cs
@@ -50,7 +50,7 @@ private static void SetTableFromSelection()
// find parent in hierarchy
var selectedTable = Selection.activeGameObject.GetComponentInParent();
- if (selectedTable != null) {
+ if (selectedTable != null && Selection.activeGameObject.activeInHierarchy) {
TableSelector.Instance.SelectedTable = selectedTable;
}
}
@@ -67,7 +67,7 @@ private static TableComponent FindTableInHierarchy()
// try root objects first
foreach (var go in rootObjects) {
var ta = go.GetComponent();
- if (ta != null) {
+ if (ta != null && ta.isActiveAndEnabled) {
return ta;
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs
index 30b1f7007..7292c8c88 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs
@@ -20,6 +20,8 @@
using System.IO;
using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine.SceneManagement;
namespace VisualPinball.Unity.Editor
{
@@ -28,6 +30,11 @@ public static class VpxMenuImporter
[MenuItem("Visual Pinball/Import VPX", false, 2)]
public static void ImportVpxIntoScene(MenuCommand menuCommand)
{
+ // if it's an untitled scene, save first.
+ if (!EnsureUntitledSceneHasBeenSaved("Before importing, you need to make your current scene an asset by saving it.")) {
+ return;
+ }
+
// open file dialog
var vpxPath = EditorUtility.OpenFilePanelWithFilters("Import .VPX File", null, new[] { "Visual Pinball Table Files", "vpx" });
if (vpxPath.Length == 0) {
@@ -36,5 +43,25 @@ public static void ImportVpxIntoScene(MenuCommand menuCommand)
VpxImportEngine.ImportIntoScene(vpxPath, tableName: Path.GetFileNameWithoutExtension(vpxPath));
}
+
+ private static bool EnsureUntitledSceneHasBeenSaved(string message)
+ {
+ if (string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) {
+
+ if (!EditorUtility.DisplayDialog("Info", "Before importing, you need to make your current scene an asset by saving it.\nSave your current scene?", "Yes", "No")) {
+ return false;
+ }
+
+ // Ask the user to save
+ EditorSceneManager.SaveOpenScenes();
+
+ // Check that the scene was saved
+ if (!string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
index e3f20caf8..6d3730a0a 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
@@ -45,9 +45,9 @@ public VpxPrefab(Object prefab, TItem item)
GameObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
GameObject!.name = item.Name;
_mainComponent = GameObject.GetComponent();
- if (_mainComponent && _mainComponent.HasProceduralMesh) {
- PrefabUtility.UnpackPrefabInstance(GameObject, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
- }
+ // if (_mainComponent && _mainComponent.HasProceduralMesh) {
+ // PrefabUtility.UnpackPrefabInstance(GameObject, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
+ // }
}
public void SetData()
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
index b55130cc9..fe26430bf 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
@@ -66,6 +66,7 @@ public class VpxSceneConverter : ITextureProvider, IMaterialProvider, IMeshProvi
private readonly Table _sourceTable;
private readonly ConvertOptions _options;
+ private Scene _tableScene;
private GameObject _tableGo;
private TableComponent _tableComponent;
private PlayfieldComponent _playfieldComponent;
@@ -167,9 +168,8 @@ public GameObject Convert(bool applyPatch = true, string tableName = null)
_patcher?.PostPatch(_tableGo);
}
- return _tableGo;
+ return MakeSubScene();
}
-
private void SaveData()
{
foreach (var key in _sourceContainer.TableInfo.Keys) {
@@ -573,6 +573,7 @@ private void CreateRootHierarchy(string tableName = null)
.Replace("%INFONAME%", _sourceContainer.InfoName);
}
+ // 1. create game object hierarchy
_tableGo = new GameObject(tableName);
_playfieldGo = new GameObject("Playfield");
var backglassGo = new GameObject("Backglass");
@@ -585,15 +586,48 @@ private void CreateRootHierarchy(string tableName = null)
backglassGo.transform.SetParent(_tableGo.transform, false);
cabinetGo.transform.SetParent(_tableGo.transform, false);
+ // 2. add components
+ _playfieldGo.AddComponent();
_playfieldComponent = _playfieldGo.AddComponent();
_playfieldGo.AddComponent();
_playfieldGo.AddComponent();
_playfieldGo.AddComponent();
- //_playfieldGo.transform.localRotation = PlayfieldComponent.GlobalRotation;
- //_playfieldGo.transform.localPosition = new Vector3(-_sourceTable.Width / 2 * PlayfieldComponent.GlobalScale, 0f, _sourceTable.Height / 2 * PlayfieldComponent.GlobalScale);
- //_playfieldGo.transform.localScale = new Vector3(PlayfieldComponent.GlobalScale, PlayfieldComponent.GlobalScale, PlayfieldComponent.GlobalScale);
_playfieldComponent.SetData(_sourceTable.Data);
}
+
+ private GameObject MakeSubScene()
+ {
+ // var sceneName = _tableScene.name;
+ // var scenePath = GetScenePath(sceneName);
+ // EditorSceneManager.SaveScene(_tableScene, scenePath);
+ // EditorSceneManager.CloseScene(_tableScene, true);
+ //
+ // // link table scene as sub scene
+ // var subSceneGo = new GameObject(sceneName);
+ // var subSceneMb = subSceneGo.AddComponent();
+ // var subSceneAsset = AssetDatabase.LoadAssetAtPath(scenePath);
+ // subSceneMb.SceneAsset = subSceneAsset;
+ //
+ // return subSceneGo;
+
+ return _tableGo;
+ }
+
+ private static string GetScenePath(string tableName)
+ {
+ const string sceneRoot = "Assets/Tables/";
+ var i = -1;
+ do {
+ var suffix = i >= 0 ? "." + i.ToString("D3") : "";
+ var scenePath = $"{sceneRoot}{tableName}{suffix}.unity";
+ if (!File.Exists(scenePath)) {
+ return scenePath;
+ }
+ i++;
+ } while (i < 999);
+
+ return null;
+ }
private GameObject GetGroupParent(IItem item) => GetGroupParent(item.ItemGroupName);
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs
new file mode 100644
index 000000000..e6ed34144
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs
@@ -0,0 +1,43 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using UnityEditor;
+using UnityEngine;
+
+namespace VisualPinball.Unity.Editor
+{
+ [CustomEditor(typeof(PhysicsEngine))]
+ public class PhysicsEngineInspector : UnityEditor.Editor
+ {
+ private SerializedProperty _gravityProperty;
+
+ private void OnEnable()
+ {
+ _gravityProperty = serializedObject.FindProperty(nameof(PhysicsEngine.GravityStrength));
+ }
+
+ public override void OnInspectorGUI()
+ {
+ EditorGUI.BeginChangeCheck();
+
+ EditorGUILayout.PropertyField(_gravityProperty, new GUIContent("Gravity Constant"));
+
+ if (EditorGUI.EndChangeCheck()) {
+ serializedObject.ApplyModifiedProperties();
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs.meta
new file mode 100644
index 000000000..d5cec9090
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PhysicsEngineInspector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c082aa8d96384de191a3ac3700f3b06b
+timeCreated: 1697578139
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PlayerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PlayerInspector.cs
index ae7b0fd4b..9c3db3957 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PlayerInspector.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/PlayerInspector.cs
@@ -14,10 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-using System.Linq;
+// ReSharper disable AssignmentInConditionalExpression
+
using UnityEditor;
using UnityEngine;
-using VisualPinball.Engine.Common;
namespace VisualPinball.Unity.Editor
{
@@ -25,23 +25,13 @@ namespace VisualPinball.Unity.Editor
[CanEditMultipleObjects]
public class PlayerInspector : UnityEditor.Editor
{
- private IPhysicsEngine[] _physicsEngines;
- private string[] _physicsEngineNames;
- private int _physicsEngineIndex;
-
- private IDebugUI[] _debugUIs;
- private string[] _debugUINames;
- private int _debugUIIndex;
-
private bool _toggleDebug = true;
private SerializedProperty _updateDuringGameplayProperty;
private void OnEnable()
{
- var player = (Player)target;
-
- _updateDuringGameplayProperty = serializedObject.FindProperty(nameof(player.UpdateDuringGamplay));
+ _updateDuringGameplayProperty = serializedObject.FindProperty(nameof(Player.UpdateDuringGamplay));
}
public override void OnInspectorGUI()
@@ -50,8 +40,6 @@ public override void OnInspectorGUI()
if (player == null) {
return;
}
- DrawEngineSelector("Physics Engine", ref player.physicsEngineId, ref _physicsEngines, ref _physicsEngineNames, ref _physicsEngineIndex);
- DrawEngineSelector("Debug UI", ref player.debugUiId, ref _debugUIs, ref _debugUINames, ref _debugUIIndex);
if (_toggleDebug = EditorGUILayout.BeginFoldoutHeaderGroup(_toggleDebug, "Debug"))
{
@@ -71,35 +59,5 @@ public override void OnInspectorGUI()
EditorGUILayout.EndFoldoutHeaderGroup();
}
-
- private void DrawEngineSelector(string engineName, ref string engineId, ref T[] instances, ref string[] names, ref int index) where T : IEngine
- {
- if (instances == null) {
- // get all instances
- instances = EngineProvider.GetAll().ToArray();
- names = instances.Select(x => x.Name).ToArray();
-
- // set the current index based on the table's ID
- index = -1;
- for (var i = 0; i < instances.Length; i++) {
- if (EngineProvider.GetId(instances[i]) == engineId) {
- index = i;
- break;
- }
- }
- if (instances.Length > 0 && index < 0) {
- index = 0;
- engineId = EngineProvider.GetId(instances[index]);
- }
- }
- if (names.Length == 0) {
- return;
- }
- var newIndex = EditorGUILayout.Popup(engineName, index, names);
- if (index != newIndex) {
- index = newIndex;
- engineId = EngineProvider.GetId(instances[newIndex]);
- }
- }
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs
index cb13b132f..9677f45c7 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs
@@ -47,6 +47,7 @@ public class TroughInspector : MainInspector
private SerializedProperty _playfieldEntrySwitchProperty;
private SerializedProperty _playfieldExitKickerProperty;
private SerializedProperty _ballCountProperty;
+ private SerializedProperty _ballProperty;
private SerializedProperty _switchCountProperty;
private SerializedProperty _jamSwitchProperty;
private SerializedProperty _rollTimeProperty;
@@ -60,6 +61,7 @@ protected override void OnEnable()
_typeProperty = serializedObject.FindProperty(nameof(TroughComponent.Type));
_playfieldEntrySwitchProperty = serializedObject.FindProperty(nameof(TroughComponent._playfieldEntrySwitch));
_playfieldExitKickerProperty = serializedObject.FindProperty(nameof(TroughComponent.PlayfieldExitKicker));
+ _ballProperty = serializedObject.FindProperty(nameof(TroughComponent.Ball));
_ballCountProperty = serializedObject.FindProperty(nameof(TroughComponent.BallCount));
_switchCountProperty = serializedObject.FindProperty(nameof(TroughComponent.SwitchCount));
_jamSwitchProperty = serializedObject.FindProperty(nameof(TroughComponent.JamSwitch));
@@ -78,6 +80,11 @@ public override void OnInspectorGUI()
DropDownProperty("Type", _typeProperty, TypeLabels, TypeValues);
+ PropertyField(_ballProperty, "Ball Prefab");
+ if (MainComponent.Ball && !MainComponent.Ball.GetComponent()) {
+ EditorGUILayout.HelpBox("Ball prefab must contain a ball component.", MessageType.Error);
+ }
+
if (MainComponent.Type != TroughType.ClassicSingleBall) {
PropertyField(_ballCountProperty);
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampListViewItemRenderer.cs
index 29cb31b4b..c5e1a0297 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampListViewItemRenderer.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampListViewItemRenderer.cs
@@ -101,7 +101,9 @@ protected override void OnIconClick(LampListData data, bool pressedDown)
var lamp = player.Lamp(data.Device);
lamp?.OnChange(pressedDown);
if (player.LampStatuses.ContainsKey(data.Id)) {
- player.LampStatuses[data.Id].IsOn = pressedDown;
+ var status = player.LampStatuses[data.Id];
+ status.IsOn = pressedDown;
+ player.LampStatuses[data.Id] = status;
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
index d47362d73..1a9abde26 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
@@ -62,6 +62,7 @@ public IconVariant(string name, IconSize size, IconColor color)
}
private const string AssetLibraryName = "asset_library";
+ private const string BallName = "ball";
private const string BallRollerName = "ball_roller";
private const string BoltName = "bolt";
private const string BumperName = "bumper";
@@ -85,6 +86,7 @@ public IconVariant(string name, IconSize size, IconColor color)
private const string PlugName = "plug";
private const string PlungerName = "plunger";
private const string PrimitiveName = "primitive";
+ private const string PhysicsName = "physics";
private const string RampName = "ramp";
private const string RotatorName = "rotator";
private const string RubberName = "rubber";
@@ -114,9 +116,9 @@ public IconVariant(string name, IconSize size, IconColor color)
private const string DisplayEventName = "display_event";
private static readonly string[] Names = {
- AssetLibraryName, BallRollerName, BoltName, BumperName, CalendarName, CannonName, CoilName, DropTargetBankName, DropTargetName, FlasherName,
+ AssetLibraryName, BallRollerName, BallName, BoltName, BumperName, CalendarName, CannonName, CoilName, DropTargetBankName, DropTargetName, FlasherName,
FlipperName, GateName, GateLifterName, HitTargetName, KeyName, KickerName, LightGroupName, LightName, MechName, MechPinMameName, PlayfieldName, PlugName,
- PlungerName, PrimitiveName, RampName, RotatorName, RubberName, ScoreReelName, ScoreReelSingleName, SlingshotName, SpinnerName, SurfaceName,
+ PhysicsName, PlungerName, PrimitiveName, RampName, RotatorName, RubberName, ScoreReelName, ScoreReelSingleName, SlingshotName, SpinnerName, SurfaceName,
SwitchNcName, SwitchNoName, TableName, TeleporterName, TriggerName, TroughName,
CoilEventName, SwitchEventName, LampEventName, LampSeqName, MetalWireGuideName,
PlayerVariableName, PlayerVariableEventName, TableVariableName, TableVariableEventName, UpdateDisplayName, DisplayEventName
@@ -163,6 +165,7 @@ private static IIconLookup[] GetLookups() {
}
public static Texture2D AssetLibrary(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(AssetLibraryName, size, color);
+ public static Texture2D Ball(IconSize size = IconSize.Small, IconColor color = IconColor.Gray) => Instance.GetItem(BallName, size, color);
public static Texture2D BallRoller(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BallRollerName, size, color);
public static Texture2D Bolt(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BoltName, size, color);
public static Texture2D Bumper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BumperName, size, color);
@@ -183,6 +186,7 @@ private static IIconLookup[] GetLookups() {
public static Texture2D Mech(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MechName, size, color);
public static Texture2D MechPinMame(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MechPinMameName, size, color);
public static Texture2D MetalWireGuide(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MetalWireGuideName, size, color);
+ public static Texture2D Physics(IconSize size = IconSize.Small, IconColor color = IconColor.Gray) => Instance.GetItem(PhysicsName, size, color);
public static Texture2D Playfield(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlayfieldName, size, color);
public static Texture2D Plug(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlugName, size, color);
public static Texture2D Plunger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlungerName, size, color);
@@ -273,6 +277,7 @@ internal class IconLookup : IIconLookup
public Texture2D Lookup(T mb, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) where T : class
{
switch (mb) {
+ case BallComponent _: return Icons.Ball(size, color);
case BallRollerComponent _: return Icons.BallRoller(size, color);
case BumperComponent _: return Icons.Bumper(size, color);
case CannonRotatorComponent _: return Icons.Cannon(size, color);
@@ -285,6 +290,7 @@ public Texture2D Lookup(T mb, IconSize size = IconSize.Large, IconColor color
case KickerComponent _: return Icons.Kicker(size, color);
case LightComponent _: return Icons.Light(size, color);
case LightGroupComponent _: return Icons.LightGroup(size, color);
+ case PhysicsEngine _: return Icons.Physics(size, color);
case PlungerComponent _: return Icons.Plunger(size, color);
case PlayfieldComponent _: return Icons.Playfield(size, color);
case PrimitiveComponent _: return Icons.Primitive(size, color);
@@ -309,6 +315,7 @@ public Texture2D Lookup(T mb, IconSize size = IconSize.Large, IconColor color
public void DisableGizmoIcons()
{
+ Icons.DisableGizmo();
Icons.DisableGizmo();
Icons.DisableGizmo();
Icons.DisableGizmo();
@@ -337,6 +344,7 @@ public void DisableGizmoIcons()
Icons.DisableGizmo();
Icons.DisableGizmo();
Icons.DisableGizmo();
+ Icons.DisableGizmo();
Icons.DisableGizmo();
Icons.DisableGizmo();
Icons.DisableGizmo();
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ColliderInspector.cs
index 5ce721c78..fb6248fdc 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ColliderInspector.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ColliderInspector.cs
@@ -80,6 +80,10 @@ public override void OnInspectorGUI()
var showColliders = EditorGUILayout.Toggle("Show Colliders", ColliderComponent.ShowColliderMesh);
refresh = refresh || showColliders != ColliderComponent.ShowColliderMesh;
ColliderComponent.ShowColliderMesh = showColliders;
+
+ var showOctree = EditorGUILayout.Toggle("Show Octree", ColliderComponent.ShowColliderOctree);
+ refresh = refresh || showOctree != ColliderComponent.ShowColliderOctree;
+ ColliderComponent.ShowColliderOctree = showOctree;
}
EditorGUILayout.EndFoldoutHeaderGroup();
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs
index baa2cb860..7ebc8219a 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs
@@ -17,7 +17,6 @@
// ReSharper disable AssignmentInConditionalExpression
using System.Linq;
-using Unity.Entities;
using UnityEditor;
using UnityEngine;
using VisualPinball.Engine.VPT.Primitive;
@@ -90,8 +89,8 @@ public static void MakePrimitive()
var cc = go.AddComponent();
cc.enabled = true;
- var cte = go.AddComponent();
- cte.ConversionMode = ConvertToEntity.Mode.ConvertAndInjectGameObject;
+ // var cte = go.AddComponent();
+ // cte.ConversionMode = ConvertToEntity.Mode.ConvertAndInjectGameObject;
}
}
@@ -117,8 +116,8 @@ public static void MakeCollider()
var cc = go.AddComponent();
cc.enabled = true;
- var cte = go.AddComponent();
- cte.ConversionMode = ConvertToEntity.Mode.ConvertAndInjectGameObject;
+ // var cte = go.AddComponent();
+ // cte.ConversionMode = ConvertToEntity.Mode.ConvertAndInjectGameObject;
}
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.asmdef b/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.asmdef
index 1cbf50624..f67a5a51e 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.asmdef
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.asmdef
@@ -2,12 +2,14 @@
"name": "VisualPinball.Unity.Editor",
"rootNamespace": "",
"references": [
+ "Unity.Collections",
"Unity.Entities",
"Unity.Entities.Hybrid",
"Unity.Formats.Fbx.Editor",
"Unity.Mathematics",
"Unity.Transforms",
"Unity.InputSystem",
+ "Unity.Scenes",
"VisualPinball.Engine",
"VisualPinball.Unity",
"VisualPinball.Unity.Patcher"
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
index 56d6183a4..c3f00d545 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
@@ -15,7 +15,6 @@
// along with this program. If not, see .
using System;
-using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
@@ -26,6 +25,7 @@
using VisualPinball.Unity.Editor;
using Light = UnityEngine.Light;
using Object = UnityEngine.Object;
+using VpeLight = VisualPinball.Engine.VPT.Light.Light;
namespace VisualPinball.Unity.Patcher
{
@@ -373,7 +373,7 @@ protected static void LightPos(GameObject go, float x, float y, float z)
///
protected static LightComponent CreateLight(string name, float x, float y, GameObject parentGo)
{
- var light = Engine.VPT.Light.Light.GetDefault(name, x, y);
+ var light = VpeLight.GetDefault(name, x, y);
light.Data.ShowBulbMesh = false;
var prefab = RenderPipeline.Current.PrefabProvider.CreateLight();
@@ -401,7 +401,7 @@ protected GameObject ConvertToInsertLight(LightComponent lo)
var name = lo.name;
var parent = lo.transform.parent.gameObject;
Object.DestroyImmediate(lo.gameObject);
- return CreateInsertLight(TableContainer.Get(name).Data, parent);
+ return CreateInsertLight(TableContainer.Get(name).Data, parent);
}
///
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json
index f86ab9853..1dc52f55f 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json
@@ -1,7 +1,9 @@
{
"dependencies": {
- "com.unity.test-framework": "1.1.31",
- "com.unity.testtools.codecoverage": "1.1.0",
+ "com.unity.ai.navigation": "1.1.5",
+ "com.unity.test-framework": "1.1.33",
+ "com.unity.testtools.codecoverage": "1.2.4",
+ "com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.6",
"com.unity.ugui": "1.0.0",
"org.visualpinball.engine.unity": "file:../../../..",
"com.unity.modules.ai": "1.0.0",
@@ -36,5 +38,13 @@
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
},
- "scopedRegistries": []
+ "scopedRegistries": [
+ {
+ "name": "VPE Registry",
+ "url": "https://registry.visualpinball.org",
+ "scopes": [
+ "com.bartofzo"
+ ]
+ }
+ ]
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json
index 54df0a3d5..b8e220bc6 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json
@@ -1,47 +1,67 @@
{
"dependencies": {
"com.autodesk.fbx": {
- "version": "4.1.1",
+ "version": "4.2.1",
"depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.burst": {
- "version": "1.6.5",
+ "com.bartofzo.nativetrees": {
+ "version": "0.1.6",
"depth": 1,
"source": "registry",
+ "dependencies": {
+ "com.unity.burst": "1.8.9",
+ "com.unity.collections": "2.1.4"
+ },
+ "url": "https://registry.visualpinball.org"
+ },
+ "com.unity.ai.navigation": {
+ "version": "1.1.5",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.modules.ai": "1.0.0"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.burst": {
+ "version": "1.8.9",
+ "depth": 2,
+ "source": "registry",
"dependencies": {
"com.unity.mathematics": "1.2.1"
},
"url": "https://packages.unity.com"
},
"com.unity.collections": {
- "version": "0.15.0-preview.21",
+ "version": "2.1.4",
"depth": 2,
"source": "registry",
"dependencies": {
- "com.unity.test-framework.performance": "2.3.1-preview",
- "com.unity.burst": "1.4.1"
+ "com.unity.burst": "1.8.4",
+ "com.unity.modules.unityanalytics": "1.0.0",
+ "com.unity.nuget.mono-cecil": "1.11.4"
},
"url": "https://packages.unity.com"
},
"com.unity.entities": {
- "version": "0.17.0-preview.42",
+ "version": "1.0.16",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.burst": "1.4.1",
- "com.unity.properties": "1.5.0-preview",
- "com.unity.serialization": "1.5.0-preview",
- "com.unity.collections": "0.15.0-preview.21",
- "com.unity.mathematics": "1.2.1",
+ "com.unity.burst": "1.8.8",
+ "com.unity.serialization": "3.1.1",
+ "com.unity.collections": "2.1.4",
+ "com.unity.mathematics": "1.2.6",
"com.unity.modules.assetbundle": "1.0.0",
- "com.unity.test-framework.performance": "2.3.1-preview",
- "com.unity.nuget.mono-cecil": "0.1.6-preview.2",
- "com.unity.jobs": "0.8.0-preview.23",
- "com.unity.scriptablebuildpipeline": "1.9.0",
- "com.unity.platforms": "0.10.0-preview.10"
+ "com.unity.modules.audio": "1.0.0",
+ "com.unity.modules.unitywebrequest": "1.0.0",
+ "com.unity.test-framework.performance": "3.0.2",
+ "com.unity.nuget.mono-cecil": "1.11.4",
+ "com.unity.scriptablebuildpipeline": "1.20.2",
+ "com.unity.profiling.core": "1.0.2"
},
"url": "https://packages.unity.com"
},
@@ -53,17 +73,17 @@
"url": "https://packages.unity.com"
},
"com.unity.formats.fbx": {
- "version": "4.1.2",
+ "version": "4.2.1",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.timeline": "1.5.2",
- "com.autodesk.fbx": "4.1.1"
+ "com.unity.timeline": "1.7.1",
+ "com.autodesk.fbx": "4.2.1"
},
"url": "https://packages.unity.com"
},
"com.unity.inputsystem": {
- "version": "1.3.0",
+ "version": "1.7.0",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -71,99 +91,69 @@
},
"url": "https://packages.unity.com"
},
- "com.unity.jobs": {
- "version": "0.8.0-preview.23",
- "depth": 1,
- "source": "registry",
- "dependencies": {
- "com.unity.collections": "0.15.0-preview.21",
- "com.unity.mathematics": "1.2.1"
- },
- "url": "https://packages.unity.com"
- },
"com.unity.mathematics": {
- "version": "1.2.5",
- "depth": 1,
+ "version": "1.2.6",
+ "depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.nuget.mono-cecil": {
- "version": "1.10.1",
+ "version": "1.11.4",
"depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.nuget.newtonsoft-json": {
- "version": "2.0.0",
- "depth": 3,
+ "com.unity.profiling.core": {
+ "version": "1.0.2",
+ "depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.platforms": {
- "version": "0.10.0-preview.10",
+ "com.unity.scriptablebuildpipeline": {
+ "version": "1.21.20",
"depth": 2,
"source": "registry",
- "dependencies": {
- "com.unity.properties": "1.6.0-preview",
- "com.unity.properties.ui": "1.6.2-preview.1",
- "com.unity.scriptablebuildpipeline": "1.6.4-preview",
- "com.unity.serialization": "1.6.2-preview"
- },
+ "dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.properties": {
- "version": "1.6.0-preview",
- "depth": 3,
+ "com.unity.serialization": {
+ "version": "3.1.1",
+ "depth": 2,
"source": "registry",
"dependencies": {
- "com.unity.nuget.mono-cecil": "0.1.6-preview.2",
- "com.unity.test-framework.performance": "2.3.1-preview"
+ "com.unity.collections": "2.1.4",
+ "com.unity.burst": "1.7.2"
},
"url": "https://packages.unity.com"
},
- "com.unity.properties.ui": {
- "version": "1.6.2-preview.1",
- "depth": 3,
+ "com.unity.settings-manager": {
+ "version": "2.0.1",
+ "depth": 1,
"source": "registry",
- "dependencies": {
- "com.unity.properties": "1.6.0-preview",
- "com.unity.serialization": "1.6.1-preview",
- "com.unity.modules.uielements": "1.0.0"
- },
+ "dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.scriptablebuildpipeline": {
- "version": "1.19.6",
- "depth": 2,
+ "com.unity.sysroot": {
+ "version": "2.0.7",
+ "depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
- "com.unity.serialization": {
- "version": "1.6.2-preview",
- "depth": 3,
+ "com.unity.sysroot.linux-x86_64": {
+ "version": "2.0.6",
+ "depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.collections": "0.12.0-preview.13",
- "com.unity.burst": "1.3.5",
- "com.unity.jobs": "0.5.0-preview.14",
- "com.unity.properties": "1.6.0-preview",
- "com.unity.test-framework.performance": "2.3.1-preview"
+ "com.unity.sysroot": "2.0.7"
},
"url": "https://packages.unity.com"
},
- "com.unity.settings-manager": {
- "version": "1.0.3",
- "depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
- },
"com.unity.test-framework": {
- "version": "1.1.31",
+ "version": "1.1.33",
"depth": 0,
"source": "registry",
"dependencies": {
@@ -174,17 +164,17 @@
"url": "https://packages.unity.com"
},
"com.unity.test-framework.performance": {
- "version": "2.3.1-preview",
+ "version": "3.0.2",
"depth": 2,
"source": "registry",
"dependencies": {
- "com.unity.test-framework": "1.1.0",
- "com.unity.nuget.newtonsoft-json": "2.0.0-preview"
+ "com.unity.test-framework": "1.1.31",
+ "com.unity.modules.jsonserialize": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.testtools.codecoverage": {
- "version": "1.1.0",
+ "version": "1.2.4",
"depth": 0,
"source": "registry",
"dependencies": {
@@ -194,7 +184,7 @@
"url": "https://packages.unity.com"
},
"com.unity.timeline": {
- "version": "1.6.4",
+ "version": "1.7.5",
"depth": 2,
"source": "registry",
"dependencies": {
@@ -205,6 +195,16 @@
},
"url": "https://packages.unity.com"
},
+ "com.unity.toolchain.win-x86_64-linux-x86_64": {
+ "version": "2.0.6",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.sysroot": "2.0.7",
+ "com.unity.sysroot.linux-x86_64": "2.0.6"
+ },
+ "url": "https://packages.unity.com"
+ },
"com.unity.ugui": {
"version": "1.0.0",
"depth": 0,
@@ -219,11 +219,9 @@
"depth": 0,
"source": "local",
"dependencies": {
- "com.unity.burst": "1.6.5",
- "com.unity.entities": "0.17.0-preview.42",
+ "com.unity.entities": "1.0.16",
+ "com.bartofzo.nativetrees": "0.1.6",
"com.unity.formats.fbx": "4.1.2",
- "com.unity.jobs": "0.8.0-preview.23",
- "com.unity.mathematics": "1.2.5",
"com.unity.inputsystem": "1.3.0",
"com.unity.ugui": "1.0.0",
"com.unity.test-framework": "1.1.31"
@@ -361,17 +359,6 @@
"version": "1.0.0",
"depth": 0,
"source": "builtin",
- "dependencies": {
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.uielementsnative": "1.0.0"
- }
- },
- "com.unity.modules.uielementsnative": {
- "version": "1.0.0",
- "depth": 1,
- "source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EntitiesClientSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EntitiesClientSettings.asset
new file mode 100644
index 000000000..3f1b7c49f
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EntitiesClientSettings.asset
@@ -0,0 +1,16 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &1
+MonoBehaviour:
+ m_ObjectHideFlags: 53
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: e2ea235c1fcfe29488ed97c467a0da53, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ FilterSettings:
+ ExcludedBakingSystemAssemblies: []
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/MemorySettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/MemorySettings.asset
new file mode 100644
index 000000000..5b5faceca
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/MemorySettings.asset
@@ -0,0 +1,35 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!387306366 &1
+MemorySettings:
+ m_ObjectHideFlags: 0
+ m_EditorMemorySettings:
+ m_MainAllocatorBlockSize: -1
+ m_ThreadAllocatorBlockSize: -1
+ m_MainGfxBlockSize: -1
+ m_ThreadGfxBlockSize: -1
+ m_CacheBlockSize: -1
+ m_TypetreeBlockSize: -1
+ m_ProfilerBlockSize: -1
+ m_ProfilerEditorBlockSize: -1
+ m_BucketAllocatorGranularity: -1
+ m_BucketAllocatorBucketsCount: -1
+ m_BucketAllocatorBlockSize: -1
+ m_BucketAllocatorBlockCount: -1
+ m_ProfilerBucketAllocatorGranularity: -1
+ m_ProfilerBucketAllocatorBucketsCount: -1
+ m_ProfilerBucketAllocatorBlockSize: -1
+ m_ProfilerBucketAllocatorBlockCount: -1
+ m_TempAllocatorSizeMain: -1
+ m_JobTempAllocatorBlockSize: -1
+ m_BackgroundJobTempAllocatorBlockSize: -1
+ m_JobTempAllocatorReducedBlockSize: -1
+ m_TempAllocatorSizeGIBakingWorker: -1
+ m_TempAllocatorSizeNavMeshWorker: -1
+ m_TempAllocatorSizeAudioWorker: -1
+ m_TempAllocatorSizeCloudWorker: -1
+ m_TempAllocatorSizeGfx: -1
+ m_TempAllocatorSizeJobWorker: -1
+ m_TempAllocatorSizeBackgroundWorker: -1
+ m_TempAllocatorSizePreloadManager: -1
+ m_PlatformMemorySettings: {}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset
index be4a7974e..08d580056 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset
@@ -12,10 +12,11 @@ MonoBehaviour:
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
- m_EnablePreviewPackages: 0
- m_EnablePackageDependencies: 0
+ m_EnablePreReleasePackages: 0
m_AdvancedSettingsExpanded: 1
m_ScopedRegistriesSettingsExpanded: 1
+ m_SeeAllPackageVersions: 0
+ m_DismissPreviewPackagesInUse: 0
oneTimeWarningShown: 0
m_Registries:
- m_Id: main
@@ -24,20 +25,20 @@ MonoBehaviour:
m_Scopes: []
m_IsDefault: 1
m_Capabilities: 7
- m_UserSelectedRegistryName:
+ m_ConfigSource: 0
+ - m_Id: scoped:project:VPE Registry
+ m_Name: VPE Registry
+ m_Url: https://registry.visualpinball.org
+ m_Scopes:
+ - com.bartofzo
+ m_IsDefault: 0
+ m_Capabilities: 0
+ m_ConfigSource: 4
+ m_UserSelectedRegistryName: VPE Registry
m_UserAddingNewScopedRegistry: 0
m_RegistryInfoDraft:
- m_ErrorMessage:
- m_Original:
- m_Id:
- m_Name:
- m_Url:
- m_Scopes: []
- m_IsDefault: 0
- m_Capabilities: 0
m_Modified: 0
- m_Name:
- m_Url:
- m_Scopes:
- -
- m_SelectedScopeIndex: 0
+ m_ErrorMessage:
+ m_UserModificationsInstanceId: -854
+ m_OriginalInstanceId: -856
+ m_LoadAssets: 0
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt
index 6b2c79b80..37f39b7bb 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 2021.3.0f1
-m_EditorVersionWithRevision: 2021.3.0f1 (6eacc8284459)
+m_EditorVersion: 2022.3.11f1
+m_EditorVersionWithRevision: 2022.3.11f1 (d00248457e15)
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs
index 9406aa9a6..f80dabd3a 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs
@@ -21,7 +21,6 @@
using VisualPinball.Engine.Test.VPT.Primitive;
using VisualPinball.Engine.VPT.Table;
using VisualPinball.Unity.Editor;
-using Assert = Unity.Assertions.Assert;
namespace VisualPinball.Unity.Test
{
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections.meta
new file mode 100644
index 000000000..40b7a7b10
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a8226ee24ab34f1ea5940bfb5736c9d5
+timeCreated: 1696369879
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs b/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs
new file mode 100644
index 000000000..f1df0a3fe
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("VisualPinball.Unity.Collections")]
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs.meta
new file mode 100644
index 000000000..bae708483
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/AssemblyInfo.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b49ec6e82c524d6f920855969a015f8f
+timeCreated: 1696368718
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs
new file mode 100644
index 000000000..4070c8752
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs
@@ -0,0 +1,100 @@
+// MIT License
+//
+// Copyright (c) 2022 Timothy Raines
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using Unity.Collections;
+using Unity.Collections.LowLevel.Unsafe;
+
+namespace VisualPinball.Unity.Collections
+{
+ ///
+ /// Part of Tertle's excellent Core extensions.
+ ///
+ /// See https://gitlab.com/tertle/com.bovinelabs.core
+ ///
+ public static unsafe class CollectionExtensions
+ {
+ ///
+ /// Returns a reference to the value associated with the specified key. Does not copy the value.
+ ///
+ /// The hashmap to retrieve the reference to the value from
+ /// The key of the hashmap pointing to the value
+ /// Type of the hashmap's key
+ /// Type of the hashmap's value
+ /// Reference to the value
+ /// Source
+ public static ref TValue GetValueByRef(this NativeParallelHashMap map, TKey key)
+ where TKey : unmanaged, IEquatable
+ where TValue : unmanaged
+ {
+ return ref map.m_HashMapData.m_Buffer->GetValueByRef(key);
+ }
+
+ /// Source
+ private static ref TValue GetValueByRef(this ref UnsafeParallelHashMapData data, TKey key)
+ where TKey : struct, IEquatable
+ where TValue : struct
+ {
+#if ENABLE_UNITY_COLLECTIONS_CHECKS
+ if (data.allocatedIndexLength <= 0)
+ {
+ throw new KeyNotFoundException();
+ }
+#endif
+
+ // First find the slot based on the hash
+ var buckets = (int*)data.buckets;
+ var bucket = key.GetHashCode() & data.bucketCapacityMask;
+ var entryIdx = buckets[bucket];
+
+ var nextPtrs = (int*)data.next;
+ while (!UnsafeUtility.ReadArrayElement(data.keys, entryIdx).Equals(key))
+ {
+ entryIdx = nextPtrs[entryIdx];
+#if ENABLE_UNITY_COLLECTIONS_CHECKS
+ if ((entryIdx < 0) || (entryIdx >= data.keyCapacity))
+ {
+ throw new KeyNotFoundException("Cannot find key " + key);
+ }
+#endif
+ }
+
+ // Read the value
+ return ref UnsafeUtility.ArrayElementAsRef(data.values, entryIdx);
+ }
+
+ #region Own stuff
+
+ public static ref T GetElementAsRef(this NativeArray array, int index) where T : unmanaged
+ {
+ return ref UnsafeUtility.ArrayElementAsRef(array.GetUnsafePtr(), index);
+ }
+
+ public static ref T GetElementAsRef(this NativeList list, int index) where T : unmanaged
+ {
+ return ref UnsafeUtility.ArrayElementAsRef(list.GetUnsafePtr(), index);
+ }
+
+ #endregion
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs.meta
new file mode 100644
index 000000000..8d7b91bbf
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionExtensions.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2d9514da4f354444b3350df327f761d8
+timeCreated: 1696368479
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref
new file mode 100644
index 000000000..369c8b2c6
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref
@@ -0,0 +1,3 @@
+{
+ "reference": "GUID:e0cd26848372d4e5c891c569017e11f1"
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref.meta
new file mode 100644
index 000000000..4c2539af2
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/CollectionReference.asmref.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a8ab32aaa18d4966b7a5974294f069c2
+timeCreated: 1696369605
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs b/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs
new file mode 100644
index 000000000..2779d7d1d
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Runtime.CompilerServices;
+using Unity.Collections;
+using UnityEngine;
+using static Unity.Mathematics.math;
+
+namespace VisualPinball.Unity.Collections
+{
+ ///
+ /// Burst friendly curve implementation used to efficiently work with animation curves in the job system.
+ ///
+ public struct NativeCurve : IDisposable
+ {
+ ///
+ /// Informs if the native data structure has an allocated memory buffer.
+ ///
+ public bool isCreated => m_Values.IsCreated;
+
+ NativeArray m_Values;
+ WrapMode m_PreWrapMode;
+ WrapMode m_PostWrapMode;
+
+ void InitializeValues(int count, Allocator allocator = Allocator.Persistent)
+ {
+ if (m_Values.IsCreated)
+ m_Values.Dispose();
+
+ m_Values = new NativeArray(count, allocator, NativeArrayOptions.UninitializedMemory);
+ }
+
+ ///
+ /// Re-initialize native curve data with new Animation curve.
+ ///
+ /// Curve ground truth to initialize from.
+ /// Number of samples to use when converting from animation curve to native curve.
+ public void Update(AnimationCurve curve, int resolution)
+ {
+ if (curve == null)
+ return;
+
+ m_PreWrapMode = curve.preWrapMode;
+ m_PostWrapMode = curve.postWrapMode;
+
+ if (!m_Values.IsCreated || m_Values.Length != resolution)
+ InitializeValues(resolution);
+
+ for (int i = 0; i < resolution; i++)
+ m_Values[i] = curve.Evaluate((float)i / (float)resolution);
+ }
+
+ ///
+ /// Evaluate value along the underlying native curve.
+ ///
+ /// Location along curve to evaluate.
+ /// Value along curve at given location t.
+ public float Evaluate(float t)
+ {
+ var count = m_Values.Length;
+
+ if (count == 1)
+ return m_Values[0];
+
+ if (t < 0f)
+ {
+ switch (m_PreWrapMode)
+ {
+ default:
+ return m_Values[0];
+ case WrapMode.Loop:
+ t = 1f - (abs(t) % 1f);
+ break;
+ case WrapMode.PingPong:
+ t = PingPong(t, 1f);
+ break;
+ }
+ }
+ else if (t > 1f)
+ {
+ switch (m_PostWrapMode)
+ {
+ default:
+ return m_Values[count - 1];
+ case WrapMode.Loop:
+ t %= 1f;
+ break;
+ case WrapMode.PingPong:
+ t = PingPong(t, 1f);
+ break;
+ }
+ }
+
+ var it = t * (count - 1);
+
+ var lower = (int)it;
+ var upper = lower + 1;
+ if (upper >= count)
+ upper = count - 1;
+
+ return lerp(m_Values[lower], m_Values[upper], it - lower);
+ }
+
+ ///
+ /// Dispose native collection.
+ ///
+ public void Dispose()
+ {
+ if (m_Values.IsCreated)
+ m_Values.Dispose();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ float Repeat(float t, float length)
+ {
+ return clamp(t - floor(t / length) * length, 0, length);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ float PingPong(float t, float length)
+ {
+ t = Repeat(t, length * 2f);
+ return length - abs(t - length);
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs.meta
new file mode 100644
index 000000000..20876e515
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/NativeCurve.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 3b29d38c75fe47968f0c82207d784ba6
+timeCreated: 1698489496
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs b/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs
new file mode 100644
index 000000000..8fac3f300
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs
@@ -0,0 +1,66 @@
+// MIT License
+//
+// Copyright (c) 2022 Timothy Raines
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System;
+using Unity.Collections.LowLevel.Unsafe;
+
+namespace VisualPinball.Unity
+{
+ public readonly unsafe struct UnmanagedArray where T : unmanaged
+ {
+ private readonly void* _buffer;
+ public readonly int Length;
+
+ public UnmanagedArray(void* buffer, int length)
+ {
+ _buffer = buffer;
+ Length = length;
+ }
+
+ public T this[int index]
+ {
+ get {
+ if (index < 0 || index >= Length) {
+ throw new IndexOutOfRangeException();
+ }
+ return UnsafeUtility.ReadArrayElement(_buffer, index);
+ }
+ }
+
+ public ref T GetAsRef(int index)
+ {
+ if (index < 0 || index >= Length) {
+ throw new IndexOutOfRangeException();
+ }
+ return ref UnsafeUtility.ArrayElementAsRef(_buffer, index);
+ }
+
+ public T[] ToArray()
+ {
+ var array = new T[Length];
+ for (var i = 0; i < Length; i++) {
+ array[i] = UnsafeUtility.ReadArrayElement(_buffer, i);
+ }
+ return array;
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs.meta
new file mode 100644
index 000000000..d95738c95
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Collections/UnmanagedArray.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b19e3cbc43a1490a80a425f1ba15d1ec
+timeCreated: 1698533074
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs b/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs
new file mode 100644
index 000000000..8428d9583
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace VisualPinball.Unity
+{
+ public static class DebugLogger
+ {
+ private const string FileName = @"C:\Temp\physdebug\vpe-2022.log";
+
+ public static void ClearLog()
+ {
+ if (File.Exists(FileName)) {
+ File.Delete(FileName);
+ }
+ }
+
+ public static void Log(string msg)
+ {
+ File.AppendAllText(FileName, msg + Environment.NewLine);
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs.meta
new file mode 100644
index 000000000..3630278de
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Common/DebugLogger.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2187d14cf7304e5b8124cf377c7b24e0
+timeCreated: 1695983818
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Common/EdgeSet.cs b/VisualPinball.Unity/VisualPinball.Unity/Common/EdgeSet.cs
index 206def19b..eaab41fbc 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Common/EdgeSet.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Common/EdgeSet.cs
@@ -14,22 +14,24 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-using System.Collections.Generic;
+using System;
+using Unity.Collections;
+using Unity.Mathematics;
namespace VisualPinball.Unity
{
- internal class EdgeSet
+ internal struct EdgeSet : IDisposable
{
- private readonly HashSet _edges;
+ private NativeParallelHashSet _edges;
- internal static EdgeSet Get()
+ internal static EdgeSet Get(Allocator allocator, int capacity = 1024)
{
- return new EdgeSet();
+ return new EdgeSet(allocator, capacity);
}
- private EdgeSet()
+ private EdgeSet(Allocator allocator, int capacity)
{
- _edges = new HashSet();
+ _edges = new NativeParallelHashSet(capacity, allocator);
}
private void Add(int i, int j) {
@@ -48,9 +50,11 @@ internal bool ShouldAddHitEdge(int i, int j) {
return false;
}
- private static long GetKey(int i, int j)
+ private static long GetKey(int i, int j) => ((long) math.min(i, j) << 32) + math.max(i, j);
+
+ public void Dispose()
{
- return ((long) System.Math.Min(i, j) << 32) + System.Math.Max(i, j);
+ _edges.Dispose();
}
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs
index 458063a31..4b2881552 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs
@@ -15,6 +15,7 @@
// along with this program. If not, see .
using System;
+using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using VisualPinball.Engine.Math;
@@ -28,19 +29,21 @@ public static class MeshExtensions
public static Mesh ToVpMesh(this UnityEngine.Mesh unityMesh)
{
+ using var meshDataArray = UnityEngine.Mesh.AcquireReadOnlyMeshData(unityMesh);
+ var meshData = meshDataArray[0];
var vpMesh = new Mesh(unityMesh.name) {
- Vertices = new Vertex3DNoTex2[unityMesh.vertexCount]
+ Vertices = new Vertex3DNoTex2[meshData.vertexCount]
};
- var unityVertices = unityMesh.vertices;
- var unityNormals = unityMesh.normals;
+ var unityVertices = new NativeArray(meshData.vertexCount, Allocator.TempJob);
+ var unityNormals = new NativeArray(meshData.vertexCount, Allocator.TempJob);
+ meshData.GetVertices(unityVertices);
+ meshData.GetNormals(unityNormals);
for (var i = 0; i < vpMesh.Vertices.Length; i++) {
- var unityVertex = unityVertices[i];
- var unityNormal = unityNormals[i];
var unityUv = unityMesh.uv[i];
vpMesh.Vertices[i] = new Vertex3DNoTex2(
- unityVertex.x, unityVertex.y, unityVertex.z,
- unityNormal.x, unityNormal.y, unityNormal.z,
+ unityVertices[i].x, unityVertices[i].y, unityVertices[i].z,
+ unityNormals[i].x, unityNormals[i].y, unityNormals[i].z,
unityUv.x, -unityUv.y );
}
vpMesh.Indices = unityMesh.triangles;
@@ -62,17 +65,18 @@ public static Mesh ToVpMesh(this UnityEngine.Mesh unityMesh)
var frameData = new Mesh.VertData[unityMesh.vertexCount];
for (var j = 0; j < unityMesh.vertexCount; j++) {
- var vertex = deltaVertices[j] + unityVertices[j];
- var normal = deltaNormals[j] + unityNormals[j];
frameData[j] = new Mesh.VertData(
- vertex.x, vertex.y, vertex.z,
- normal.x, normal.y, normal.z);
+ deltaVertices[j].x + unityVertices[j].x, deltaVertices[j].y + unityVertices[j].y, deltaVertices[j].z + unityVertices[j].z,
+ deltaNormals[j].x + unityNormals[j].x, deltaNormals[j].y + unityNormals[j].y, deltaNormals[j].z + unityNormals[j].z);
}
vpMesh.AnimationFrames.Add(frameData);
}
}
+ unityVertices.Dispose();
+ unityNormals.Dispose();
+
return vpMesh;
}
@@ -152,4 +156,3 @@ public static Vector3 ToUnityNormalVector3(this Mesh.VertData vpVert)
}
}
}
-
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
index 436b94824..2b450be6a 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
@@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-using Unity.Collections;
-using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
@@ -24,15 +22,14 @@ namespace VisualPinball.Unity
{
public class BallRollerComponent : MonoBehaviour
{
+ private PhysicsEngine _physicsEngine;
private PlayfieldComponent _playfield;
private Matrix4x4 _ltw;
private Matrix4x4 _wtl;
private Plane _playfieldPlane;
- private EntityManager _entityManager;
- private Entity _ballEntity = Entity.Null;
- private EntityQuery _ballEntityQuery;
+ private int _ballId = 0;
private void Awake()
{
@@ -46,9 +43,7 @@ private void Awake()
var p2 = _ltw.MultiplyPoint(new Vector3(100f, 100f, z));
var p3 = _ltw.MultiplyPoint(new Vector3(100f, -100f, z));
_playfieldPlane.Set3Points(p1, p2, p3);
-
- _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
- _ballEntityQuery = _entityManager.CreateEntityQuery(typeof(BallData));
+ _physicsEngine = GetComponentInChildren();
}
private void Update()
@@ -60,21 +55,24 @@ private void Update()
// find nearest ball
if (Mouse.current.middleButton.wasPressedThisFrame) {
if (GetCursorPositionOnPlayfield(out var mousePosition)) {
- var ballEntities = _ballEntityQuery.ToEntityArray(Allocator.Temp);
var nearestDistance = float.PositiveInfinity;
- BallData nearestBall = default;
+ BallState nearestBall = default;
var ballFound = false;
- foreach (var ballEntity in ballEntities) {
- var ballData = _entityManager.GetComponentData(ballEntity);
- if (ballData.IsFrozen) {
- continue;
- }
- var distance = math.distance(mousePosition, ballData.Position.xy);
- if (distance < nearestDistance) {
- nearestDistance = distance;
- nearestBall = ballData;
- ballFound = true;
- _ballEntity = ballEntity;
+
+ using (var enumerator = _physicsEngine.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ var ball = enumerator.Current.Value;
+
+ if (ball.IsFrozen) {
+ continue;
+ }
+ var distance = math.distance(mousePosition, ball.Position.xy);
+ if (distance < nearestDistance) {
+ nearestDistance = distance;
+ nearestBall = ball;
+ ballFound = true;
+ _ballId = ball.Id;
+ }
}
}
@@ -83,26 +81,24 @@ private void Update()
}
}
- } else if (Mouse.current.middleButton.isPressed && _ballEntity != Entity.Null) {
+ } else if (Mouse.current.middleButton.isPressed && _ballId != 0) {
if (GetCursorPositionOnPlayfield(out var mousePosition)) {
- var ballData = _entityManager.GetComponentData(_ballEntity);
- UpdateBall(ref ballData, mousePosition);
+ ref var ball = ref _physicsEngine.BallState(_ballId);
+ UpdateBall(ref ball, mousePosition);
}
}
- if (Mouse.current.middleButton.wasReleasedThisFrame && _ballEntity != Entity.Null) {
- var ballData = _entityManager.GetComponentData(_ballEntity);
+ if (Mouse.current.middleButton.wasReleasedThisFrame && _ballId != 0) {
+ ref var ballData = ref _physicsEngine.BallState(_ballId);
ballData.ManualControl = false;
- _entityManager.SetComponentData(_ballEntity, ballData);
- _ballEntity = Entity.Null;
+ _ballId = 0;
}
}
- private void UpdateBall(ref BallData ballData, float2 position)
+ private void UpdateBall(ref BallState ballState, float2 position)
{
- ballData.ManualControl = true;
- ballData.ManualPosition = position;
- _entityManager.SetComponentData(_ballEntity, ballData);
+ ballState.ManualControl = true;
+ ballState.ManualPosition = position;
}
private bool GetCursorPositionOnPlayfield(out float2 position)
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs
index f59d8b3c3..0da2e2d91 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs
@@ -51,12 +51,11 @@ private void Start()
{
var playfield = FindObjectOfType();
- var pfr = playfield.GetComponent();
- if (pfr) {
+ var pfr = playfield == null ? null : playfield.GetComponent();
+ if (pfr != null) {
positionOffset = pfr.bounds.center;
}
-
_radius = Vector3.Distance(Vector3.zero, transform.position);
transformCache = transform;
_focusPoint = transformCache.forward * -1f * _radius;
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs
index 75fa703f9..d0b5c4316 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs
@@ -77,7 +77,7 @@ public void OnStart()
// check if device exists
if (!_coilDevices.ContainsKey(coilMapping.Device)) {
- Logger.Error($"Unknown coil device \"{coilMapping.Device.name}\".");
+ Logger.Warn($"Unknown coil device \"{coilMapping.Device.name}\".");
break;
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
index 1c4b945b6..31e4e14e7 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
@@ -15,7 +15,6 @@
// along with this program. If not, see .
using System;
-using Unity.Entities;
namespace VisualPinball.Unity
{
@@ -52,11 +51,11 @@ public class DeviceSwitch : IApiSwitch
private readonly SwitchDefault _switchDefault;
private readonly SwitchHandler _switchHandler;
- public DeviceSwitch(string name, bool isPulseSwitch, SwitchDefault switchDefault, Player player)
+ public DeviceSwitch(string name, bool isPulseSwitch, SwitchDefault switchDefault, Player player, PhysicsEngine physicsEngine)
{
_isPulseSwitch = isPulseSwitch;
_switchDefault = switchDefault;
- _switchHandler = new SwitchHandler(name, player);
+ _switchHandler = new SwitchHandler(name, player, physicsEngine);
}
IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig, IApiSwitchStatus switchStatus) =>
@@ -71,7 +70,7 @@ IApiSwitchStatus IApiSwitch.AddSwitchDest(SwitchConfig switchConfig, IApiSwitchS
public void SetSwitch(bool enabled)
{
_switchHandler.OnSwitch(enabled);
- Switch?.Invoke(this, new SwitchEventArgs(enabled, Entity.Null));
+ Switch?.Invoke(this, new SwitchEventArgs(enabled));
}
///
@@ -85,7 +84,7 @@ public void ScheduleSwitch(bool enabled, int delay)
SetSwitch(enabled);
} else {
_switchHandler.ScheduleSwitch(enabled, delay, isEnabled => {
- Switch?.Invoke(this, new SwitchEventArgs(isEnabled, Entity.Null));
+ Switch?.Invoke(this, new SwitchEventArgs(isEnabled));
});
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
index 6d237596e..7f6c21b5b 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
@@ -74,7 +74,7 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
private const string SwMotorEnd = "s_motor_end";
public GamelogicEngineSwitch[] RequestedSwitches => _availableSwitches.ToArray();
- private readonly List _availableSwitches = new List {
+ private readonly List _availableSwitches = new() {
new GamelogicEngineSwitch(SwLeftFlipper) { Description = "Left Flipper (Button)", InputActionHint = InputConstants.ActionLeftFlipper },
new GamelogicEngineSwitch(SwRightFlipper) { Description = "Right Flipper (Button)", InputActionHint = InputConstants.ActionRightFlipper },
new GamelogicEngineSwitch(SwTroughDrain) { Description = "Trough Drain", DeviceHint = "^Trough\\s*\\d?", DeviceItemHint = TroughComponent.EntrySwitchId },
@@ -102,7 +102,8 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
public DisplayConfig[] RequiredDisplays => new[] { new DisplayConfig(DisplayDmd, DmdWidth, DmdHeight) };
public GamelogicEngineCoil[] RequestedCoils => _availableCoils.ToArray();
- private readonly List _availableCoils = new List {
+ private readonly List _availableCoils = new()
+ {
new GamelogicEngineCoil(CoilLeftFlipperMain) { Description = "Left Flipper (Main)", DeviceHint = "^(LeftFlipper|LFlipper|FlipperLeft|FlipperL)$", DeviceItemHint = FlipperComponent.MainCoilItem },
new GamelogicEngineCoil(CoilLeftFlipperHold) { Description = "Left Flipper (Hold)", DeviceHint = "^(LeftFlipper|LFlipper|FlipperLeft|FlipperL)$", DeviceItemHint = FlipperComponent.HoldCoilItem },
new GamelogicEngineCoil(CoilRightFlipperMain) { Description = "Right Flipper (Main)", DeviceHint = "^(RightFlipper|RFlipper|FlipperRight|FlipperR)$", DeviceItemHint = FlipperComponent.MainCoilItem },
@@ -113,8 +114,8 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
};
public GamelogicEngineWire[] AvailableWires { get; } = {
- new GamelogicEngineWire(SwLeftFlipper, CoilLeftFlipperMain, DestinationType.Coil, "Left Flipper"),
- new GamelogicEngineWire(SwRightFlipper, CoilRightFlipperMain, DestinationType.Coil, "Right Flipper"),
+ new(SwLeftFlipper, CoilLeftFlipperMain, DestinationType.Coil, "Left Flipper"),
+ new(SwRightFlipper, CoilRightFlipperMain, DestinationType.Coil, "Right Flipper"),
};
private const string GiSlingshotRightLower = "gi_1";
@@ -137,32 +138,32 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
private const string LampRedBumper = "l_bumper";
public GamelogicEngineLamp[] RequestedLamps { get; } = {
- new GamelogicEngineLamp(GiSlingshotRightLower) { Description = "Right Slingshot (lower)", DeviceHint = "gi1$" },
- new GamelogicEngineLamp(GiSlingshotRightUpper) { Description = "Right Slingshot (upper)", DeviceHint = "gi2$" },
- new GamelogicEngineLamp(GiSlingshotLeftLower) { Description = "Left Slingshot (lower)", DeviceHint = "gi3$" },
- new GamelogicEngineLamp(GiSlingshotLeftUpper) { Description = "Left Slingshot (upper)", DeviceHint = "gi4$" },
- new GamelogicEngineLamp(GiDropTargetsRightLower) { Description = "Right Drop Targets (lower)", DeviceHint = "gi5$" },
- new GamelogicEngineLamp(GiDropTargetsRightUpper) { Description = "Right Drop Targets (upper)", DeviceHint = "gi8$" },
- new GamelogicEngineLamp(GiDropTargetsLeftLower) { Description = "Left Drop Targets (lower)", DeviceHint = "gi6$" },
- new GamelogicEngineLamp(GiDropTargetsLeftUpper) { Description = "Left Drop Targets (upper)", DeviceHint = "gi7$" },
- new GamelogicEngineLamp(GiTop1) { Description = "Top 1 (left)", DeviceHint = "gi13$" },
- new GamelogicEngineLamp(GiTop2) { Description = "Top 2", DeviceHint = "gi10$" },
- new GamelogicEngineLamp(GiTop3) { Description = "Top 3", DeviceHint = "gi9$" },
- new GamelogicEngineLamp(GiTop4) { Description = "Top 4", DeviceHint = "gi11$" },
- new GamelogicEngineLamp(GiTop5) { Description = "Top 5 (right)", DeviceHint = "gi12$" },
- new GamelogicEngineLamp(GiLowerRamp) { Description = "Ramp (lower)", DeviceHint = "gi14$" },
- new GamelogicEngineLamp(GiUpperRamp) { Description = "Ramp (upper)", DeviceHint = "gi15$" },
- new GamelogicEngineLamp(GiTopLeftPlastic) { Description = "Top Left Plastics", DeviceHint = "gi16$" },
- new GamelogicEngineLamp(LampRedBumper) { Description = "Red Bumper", DeviceHint = "^b1l2$" }
+ new(GiSlingshotRightLower) { Description = "Right Slingshot (lower)", DeviceHint = "gi1$" },
+ new(GiSlingshotRightUpper) { Description = "Right Slingshot (upper)", DeviceHint = "gi2$" },
+ new(GiSlingshotLeftLower) { Description = "Left Slingshot (lower)", DeviceHint = "gi3$" },
+ new(GiSlingshotLeftUpper) { Description = "Left Slingshot (upper)", DeviceHint = "gi4$" },
+ new(GiDropTargetsRightLower) { Description = "Right Drop Targets (lower)", DeviceHint = "gi5$" },
+ new(GiDropTargetsRightUpper) { Description = "Right Drop Targets (upper)", DeviceHint = "gi8$" },
+ new(GiDropTargetsLeftLower) { Description = "Left Drop Targets (lower)", DeviceHint = "gi6$" },
+ new(GiDropTargetsLeftUpper) { Description = "Left Drop Targets (upper)", DeviceHint = "gi7$" },
+ new(GiTop1) { Description = "Top 1 (left)", DeviceHint = "gi13$" },
+ new(GiTop2) { Description = "Top 2", DeviceHint = "gi10$" },
+ new(GiTop3) { Description = "Top 3", DeviceHint = "gi9$" },
+ new(GiTop4) { Description = "Top 4", DeviceHint = "gi11$" },
+ new(GiTop5) { Description = "Top 5 (right)", DeviceHint = "gi12$" },
+ new(GiLowerRamp) { Description = "Ramp (lower)", DeviceHint = "gi14$" },
+ new(GiUpperRamp) { Description = "Ramp (upper)", DeviceHint = "gi15$" },
+ new(GiTopLeftPlastic) { Description = "Top Left Plastics", DeviceHint = "gi16$" },
+ new(LampRedBumper) { Description = "Red Bumper", DeviceHint = "^b1l2$" }
};
private Player _player;
private BallManager _ballManager;
private bool _frameSent;
private PlayfieldComponent _playfieldComponent;
- private const float FlipperLag = 0.5f;
+ private const float FlipperLag = 0f;
- private readonly Dictionary _switchTime = new Dictionary();
+ private readonly Dictionary _switchTime = new();
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs
new file mode 100644
index 000000000..9ec27e078
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs
@@ -0,0 +1,93 @@
+using System;
+using Unity.Collections;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ internal struct InsideOfs : IDisposable
+ {
+ private NativeParallelHashMap _bitLookup;
+ private NativeParallelHashMap _insideOfs;
+
+ public InsideOfs(Allocator allocator)
+ {
+ _bitLookup = new NativeParallelHashMap(64, allocator);
+ _insideOfs = new NativeParallelHashMap(64, allocator);
+ }
+
+ internal void SetInsideOf(int itemId, int ballId)
+ {
+ if (!_insideOfs.ContainsKey(itemId)) {
+ _insideOfs.Add(itemId, new BitField64());
+ }
+
+ ref var bits = ref _insideOfs.GetValueByRef(itemId);
+ bits.SetBits(GetBitIndex(ballId), true);
+ }
+
+ internal void SetOutsideOf(int itemId, int ballId)
+ {
+ if (!_insideOfs.ContainsKey(itemId)) {
+ return;
+ }
+
+ ref var bits = ref _insideOfs.GetValueByRef(itemId);
+ bits.SetBits(GetBitIndex(ballId), false);
+ ClearBitIndex(ballId);
+ ClearItems(itemId);
+ }
+
+ internal bool IsInsideOf(int itemId, int ballId)
+ {
+ return _insideOfs.ContainsKey(itemId) && _insideOfs[itemId].IsSet(GetBitIndex(ballId));
+ }
+
+ internal bool IsOutsideOf(int itemId, int ballId) => !IsInsideOf(itemId, ballId);
+
+ private void ClearItems(int itemId)
+ {
+ if (_insideOfs[itemId].GetBits(0, 64) == 0L) {
+ _insideOfs.Remove(itemId);
+ }
+ }
+
+ private void ClearBitIndex(int ballId)
+ {
+ var maps = _insideOfs.GetValueArray(Allocator.Temp);
+ var index = GetBitIndex(ballId);
+ foreach (var ballIndices in maps) {
+ if (!ballIndices.IsSet(index)) {
+ continue;
+ }
+ maps.Dispose();
+ return;
+ }
+ _bitLookup.Remove(ballId);
+ }
+
+ private int GetBitIndex(int ballId)
+ {
+ if (_bitLookup.ContainsKey(ballId)) {
+ return _bitLookup[ballId];
+ }
+
+ var indices = _bitLookup.GetValueArray(Allocator.Temp);
+ for (var i = 0; i < 64; i++) {
+ if (indices.Contains(i)) {
+ continue;
+ }
+ _bitLookup[ballId] = i;
+ indices.Dispose();
+ return i;
+ }
+ throw new IndexOutOfRangeException();
+ }
+
+
+ public void Dispose()
+ {
+ _bitLookup.Dispose();
+ _insideOfs.Dispose();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs.meta
new file mode 100644
index 000000000..95c048567
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/InsideOfs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 39439753f2f64ab3ace90deff7a74ae7
+timeCreated: 1681344266
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs
index 0d909bef6..34fa7aca5 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs
@@ -98,38 +98,57 @@ public void OnStart()
private void HandleLampsEvent(object sender, LampsEventArgs lampsEvent)
{
+ LampAction action = default;
foreach (var lampEvent in lampsEvent.LampsChanged) {
- Apply(lampEvent.Id, lampEvent.Source, lampEvent.IsCoil, (state, lamp, mapping) => ApplyValue(lampEvent.Id, lampEvent.Value, state, lamp, mapping));
+ if (Apply(lampEvent.Id, lampEvent.Source, lampEvent.IsCoil, ref action)) {
+ ApplyValue(lampEvent.Id, lampEvent.Value, action.State, action.Lamp, action.Mapping);
+ }
}
}
private void HandleLampEvent(object sender, LampEventArgs lampEvent)
{
- Apply(lampEvent.Id, lampEvent.Source, lampEvent.IsCoil, (state, lamp, mapping) => ApplyValue(lampEvent.Id, lampEvent.Value, state, lamp, mapping));
+ LampAction action = default;
+ if (Apply(lampEvent.Id, lampEvent.Source, lampEvent.IsCoil, ref action)) {
+ ApplyValue(lampEvent.Id, lampEvent.Value, action.State, action.Lamp, action.Mapping);
+ }
}
public void HandleLampEvent(string id, float value)
{
- Apply(id, LampSource.Lamp, false, (state, lamp, mapping) => ApplyValue(id, value, state, lamp, mapping));
+ LampAction action = default;
+ if (Apply(id, LampSource.Lamp, false, ref action)) {
+ ApplyValue(id, value, action.State, action.Lamp, action.Mapping);
+ }
}
public void HandleLampEvent(string id, LampStatus status)
{
- Apply(id, LampSource.Lamp, false, (state, lamp, _) => ApplyStatus(id, status, state, lamp));
+ LampAction action = default;
+ if (Apply(id, LampSource.Lamp, false, ref action)) {
+ ApplyStatus(id, status, action.State, action.Lamp);
+ }
}
public void HandleLampEvent(string id, Color color)
{
- Apply(id, LampSource.Lamp, false, (state, lamp, _) => ApplyColor(id, color, state, lamp));
+ LampAction action = default;
+ if (Apply(id, LampSource.Lamp, false, ref action)) {
+ ApplyColor(id, color, action.State, action.Lamp);
+ }
}
public void HandleCoilEvent(string id, bool isEnabled)
{
- Apply(id, LampSource.Lamp, true, (state, lamp, _) => ApplyStatus(id, isEnabled ? LampStatus.On : LampStatus.Off, state, lamp));
+ LampAction action = default;
+ if (Apply(id, LampSource.Lamp, true, ref action)) {
+ ApplyStatus(id, isEnabled ? LampStatus.On : LampStatus.Off, action.State, action.Lamp);
+ }
}
- private void Apply(string id, LampSource lampSource, bool isCoil, Action action)
+ private bool Apply(string id, LampSource lampSource, bool isCoil, ref LampAction action)
{
+ var hasChanged = false;
if (_lampAssignments.ContainsKey(id)) {
foreach (var component in _lampAssignments[id]) {
var mapping = _lampMappings[id][component];
@@ -141,20 +160,21 @@ private void Apply(string id, LampSource lampSource, bool isCoil, Action .
+
+using System;
+using NativeTrees;
+using Unity.Collections;
+using Unity.Profiling;
+using VisualPinball.Engine.Common;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ public struct PhysicsCycle : IDisposable
+ {
+ private NativeList _contacts;
+
+ private static readonly ProfilerMarker PerfMarker = new("PhysicsCycle");
+ private static readonly ProfilerMarker PerfMarkerDisplacement = new("Displacement");
+ private static readonly ProfilerMarker PerfMarkerCollision = new("Collision");
+ private static readonly ProfilerMarker PerfMarkerContacts = new("Contacts");
+
+ public PhysicsCycle(Allocator a)
+ {
+ _contacts = new NativeList(a);
+ }
+
+ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref NativeParallelHashSet overlappingColliders, float dTime)
+ {
+ PerfMarker.Begin();
+ var staticCounts = PhysicsConstants.StaticCnts;
+
+ while (dTime > 0) {
+
+ var hitTime = dTime; // begin time search from now ... until delta ends
+
+ ApplyFlipperTime(ref hitTime, ref state);
+
+ // clear contacts
+ _contacts.Clear();
+
+ // create octree of ball-to-ball collision
+ var ballOctree = PhysicsDynamicBroadPhase.CreateOctree(ref state.Balls, in playfieldBounds);
+
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var ball = ref enumerator.Current.Value;
+
+ if (ball.IsFrozen) {
+ continue;
+ }
+
+ // hit testing
+ PhysicsStaticBroadPhase.FindOverlaps(in state.Octree, in ball, ref overlappingColliders);
+ PhysicsStaticNarrowPhase.FindNextCollision(hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state);
+ PhysicsDynamicBroadPhase.FindOverlaps(in ballOctree, in ball, ref overlappingColliders, ref state.Balls);
+ PhysicsDynamicNarrowPhase.FindNextCollision(ref ball, ref overlappingColliders, ref _contacts, ref state);
+
+ // apply static time
+ ApplyStaticTime(ref hitTime, ref staticCounts, in ball);
+ }
+ }
+
+ #region Displacement
+ PerfMarkerDisplacement.Begin();
+
+ // balls
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ BallDisplacementPhysics.UpdateDisplacements(ref enumerator.Current.Value, hitTime); // use static method instead of member
+ }
+ }
+ // flippers
+ using (var enumerator = state.FlipperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var flipperState = ref enumerator.Current.Value;
+ FlipperDisplacementPhysics.UpdateDisplacement(flipperState.ItemId, ref flipperState.Movement,
+ ref flipperState.Tricks, in flipperState.Static, hitTime, ref state.EventQueue);
+ }
+ }
+ // gates
+ using (var enumerator = state.GateStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var gateState = ref enumerator.Current.Value;
+ GateDisplacementPhysics.UpdateDisplacement(gateState.ItemId, ref gateState.Movement, in gateState.Static,
+ hitTime, ref state.EventQueue);
+ }
+ }
+ // plunger
+ using (var enumerator = state.PlungerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var plungerState = ref enumerator.Current.Value;
+ PlungerDisplacementPhysics.UpdateDisplacement(plungerState.ItemId, ref plungerState.Movement, ref plungerState.Collider,
+ in plungerState.Static, hitTime, ref state.EventQueue);
+ }
+ }
+ // spinners
+ using (var enumerator = state.SpinnerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var spinnerState = ref enumerator.Current.Value;
+ SpinnerDisplacementPhysics.UpdateDisplacement(spinnerState.ItemId, ref spinnerState.Movement, in spinnerState.Static,
+ hitTime, ref state.EventQueue);
+ }
+ }
+
+ PerfMarkerDisplacement.End();
+ #endregion
+
+ // collision
+ PerfMarkerCollision.Begin();
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var ball = ref enumerator.Current.Value;
+
+ // dynamic collision
+ PhysicsDynamicCollision.Collide(hitTime, ref ball, ref state);
+
+ // static collision
+ PhysicsStaticCollision.Collide(hitTime, ref ball, ref state);
+ }
+ }
+ PerfMarkerCollision.End();
+
+ // handle contacts
+ PerfMarkerContacts.Begin();
+ for (var i = 0; i < _contacts.Length; i++) {
+ ref var contact = ref _contacts.GetElementAsRef(i);
+ ref var ball = ref state.Balls.GetValueByRef(contact.BallId);
+ ContactPhysics.Update(ref contact, ref ball, ref state, hitTime);
+ }
+ PerfMarkerContacts.End();
+
+ // clear contacts
+ _contacts.Clear();
+
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var ball = ref enumerator.Current.Value;
+ BallSpinHackPhysics.Update(ref ball);
+ }
+ }
+
+ dTime -= hitTime;
+
+ state.SwapBallCollisionHandling = !state.SwapBallCollisionHandling;
+ }
+ PerfMarker.End();
+ }
+
+ private static void ApplyStaticTime(ref float hitTime, ref float staticCounts, in BallState ball)
+ {
+ // for each collision event
+ var collEvent = ball.CollisionEvent;
+ if (collEvent.HasCollider() && collEvent.HitTime <= hitTime) { // smaller hit time??
+ hitTime = collEvent.HitTime; // record actual event time
+ if (hitTime < PhysicsConstants.StaticTime) { // less than static time interval
+ if (--staticCounts < 0) {
+ staticCounts = 0; // keep from wrapping
+ hitTime = PhysicsConstants.StaticTime;
+ }
+ }
+ }
+ }
+
+ private void ApplyFlipperTime(ref float hitTime, ref PhysicsState state)
+ {
+ // for each flipper
+ using (var enumerator = state.FlipperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var flipperState = ref enumerator.Current.Value;
+ var flipperHitTime = flipperState.Movement.GetHitTime(flipperState.Static.AngleStart, flipperState.Tricks.AngleEnd);
+
+ // if flipper comes to a rest before the end of the cycle, advance to that time
+ if (flipperHitTime > 0 && flipperHitTime < hitTime) { //!! >= 0.f causes infinite loop
+ hitTime = flipperHitTime;
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ _contacts.Dispose();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs.meta
new file mode 100644
index 000000000..7e9bb7946
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 21428d2788334ad59c3394263748202c
+timeCreated: 1678661168
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs
new file mode 100644
index 000000000..ffa298ccb
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs
@@ -0,0 +1,58 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using NativeTrees;
+using Unity.Collections;
+using Unity.Profiling;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ public static class PhysicsDynamicBroadPhase
+ {
+ private static readonly ProfilerMarker PerfMarkerBallOctree = new("CreateBallOctree");
+ private static readonly ProfilerMarker PerfMarkerDynamicBroadPhase = new("DynamicBroadPhase");
+
+ internal static NativeOctree CreateOctree(ref NativeParallelHashMap balls, in AABB playfieldBounds)
+ {
+ PerfMarkerBallOctree.Begin();
+ var octree = new NativeOctree(playfieldBounds, 16, 10, Allocator.TempJob);
+ using var enumerator = balls.GetEnumerator();
+ while (enumerator.MoveNext()) {
+ ref var ball = ref enumerator.Current.Value;
+ octree.Insert(ball.Id, ball.Aabb);
+ }
+ PerfMarkerBallOctree.End();
+ return octree;
+ }
+
+ internal static void FindOverlaps(in NativeOctree octree, in BallState ball, ref NativeParallelHashSet overlappingBalls, ref NativeParallelHashMap balls)
+ {
+ PerfMarkerDynamicBroadPhase.Begin();
+ overlappingBalls.Clear();
+ octree.RangeAABBUnique(ball.Aabb, overlappingBalls);
+ using var ob = overlappingBalls.ToNativeArray(Allocator.Temp);
+ for (var i = 0; i < ob.Length; i ++) {
+ var overlappingBallId = ob[i];
+ ref var overlappingBall = ref balls.GetValueByRef(overlappingBallId);
+ if (overlappingBallId == ball.Id || overlappingBall.IsFrozen) {
+ overlappingBalls.Remove(overlappingBallId);
+ }
+ }
+ PerfMarkerDynamicBroadPhase.End();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs.meta
new file mode 100644
index 000000000..fe393901e
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicBroadPhase.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 39f41526d2d74c068970e5b36dbfaca8
+timeCreated: 1697322346
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs
new file mode 100644
index 000000000..553e4fab6
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs
@@ -0,0 +1,54 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using Unity.Profiling;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ internal static class PhysicsDynamicCollision
+ {
+ private static readonly ProfilerMarker PerfMarker = new("DynamicCollision");
+
+ internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState state)
+ {
+ // pick "other" ball
+ ref var collEvent = ref ball.CollisionEvent;
+ ref var otherId = ref collEvent.BallId;
+
+ // find balls with hit objects and minimum time
+ if (otherId != 0 && collEvent.HitTime <= hitTime) {
+
+ PerfMarker.Begin();
+
+ ref var otherBall = ref state.Balls.GetValueByRef(otherId);
+ ref var otherCollEvent = ref otherBall.CollisionEvent;
+
+ // now collision, contact and script reactions on active ball (object)+++++++++
+
+ //this.activeBall = ball; // For script that wants the ball doing the collision
+
+ BallCollider.Collide(ref otherBall, ref ball, in otherCollEvent, in collEvent,
+ state.SwapBallCollisionHandling);
+
+ // remove trial hit object pointer
+ collEvent.ClearCollider();
+
+ PerfMarker.End();
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs.meta
new file mode 100644
index 000000000..2f3439dde
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicCollision.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a8a75d40ec354691b6de0c39c1950933
+timeCreated: 1697366994
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs
new file mode 100644
index 000000000..05a25fb3f
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs
@@ -0,0 +1,60 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using Unity.Collections;
+using Unity.Profiling;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ internal static class PhysicsDynamicNarrowPhase
+ {
+ private static readonly ProfilerMarker PerfMarkerDynamicNarrowPhase = new("DynamicNarrowPhase");
+
+ internal static void FindNextCollision(ref BallState ball, ref NativeParallelHashSet collidingBalls,
+ ref NativeList contacts, ref PhysicsState state)
+ {
+ // don't play with frozen balls
+ if (ball.IsFrozen) {
+ return;
+ }
+ PerfMarkerDynamicNarrowPhase.Begin();
+
+ ref var collEvent = ref ball.CollisionEvent;
+ using var enumerator = collidingBalls.GetEnumerator();
+ while (enumerator.MoveNext()) {
+ var collidingBallId = enumerator.Current;
+ ref var collBall = ref state.Balls.GetValueByRef(collidingBallId);
+
+ var newCollEvent = new CollisionEventData();
+ var newTime = BallCollider.HitTest(ref newCollEvent, ref ball, in collBall, collEvent.HitTime);
+ var validHit = newTime >= 0 && !Math.Sign(newTime) && newTime <= collEvent.HitTime;
+
+ if (newCollEvent.IsContact || validHit) {
+ newCollEvent.SetBallItem(collidingBallId);
+ newCollEvent.HitTime = newTime;
+ if (newCollEvent.IsContact) {
+ contacts.Add(new ContactBufferElement(ball.Id, newCollEvent));
+
+ } else { // if (validhit)
+ collEvent = newCollEvent;
+ }
+ }
+ }
+ PerfMarkerDynamicNarrowPhase.End();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs.meta
new file mode 100644
index 000000000..cc0db2515
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsDynamicNarrowPhase.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f8ac8708494e49e28d99ed310112d4c9
+timeCreated: 1697365085
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs
new file mode 100644
index 000000000..b6fb6007c
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs
@@ -0,0 +1,421 @@
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// ReSharper disable InconsistentNaming
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using NativeTrees;
+using Unity.Collections;
+using Unity.Jobs;
+using Unity.Mathematics;
+using UnityEngine;
+using VisualPinball.Engine.Common;
+using VisualPinball.Unity.Collections;
+using AABB = NativeTrees.AABB;
+using Debug = UnityEngine.Debug;
+
+namespace VisualPinball.Unity
+{
+ public class PhysicsEngine : MonoBehaviour
+ {
+ #region Configuration
+
+ [Tooltip("Gravity constant, in VPX units.")]
+ public float GravityStrength = PhysicsConstants.GravityConst * PhysicsConstants.DefaultTableGravity;
+
+ #endregion
+
+ #region States
+
+ [NonSerialized] private AABB _playfieldBounds;
+ [NonSerialized] private InsideOfs _insideOfs;
+ [NonSerialized] private NativeOctree _octree;
+ [NonSerialized] private NativeColliders _colliders;
+ [NonSerialized] private NativeArray _physicsEnv = new(1, Allocator.Persistent);
+ [NonSerialized] private NativeQueue _eventQueue = new(Allocator.Persistent);
+
+ [NonSerialized] private NativeParallelHashMap _ballStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _bumperStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _flipperStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _gateStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _dropTargetStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _hitTargetStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _kickerStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _plungerStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _spinnerStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _surfaceStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashMap _triggerStates = new(0, Allocator.Persistent);
+ [NonSerialized] private NativeParallelHashSet _disabledCollisionItems = new(0, Allocator.Persistent);
+ [NonSerialized] private bool _swapBallCollisionHandling;
+
+ #endregion
+
+ #region Transforms
+
+ [NonSerialized] private readonly Dictionary _transforms = new();
+ [NonSerialized] private readonly Dictionary _skinnedMeshRenderers = new();
+
+ #endregion
+
+ [NonSerialized] private readonly Queue _inputActions = new();
+ [NonSerialized] private readonly List _scheduledActions = new();
+
+ [NonSerialized] private Player _player;
+
+ private static ulong NowUsec => (ulong)(Time.timeAsDouble * 1000000);
+
+ #region API
+
+ public void ScheduleAction(int timeoutMs, Action action) => ScheduleAction((uint)timeoutMs, action);
+ public void ScheduleAction(uint timeoutMs, Action action)
+ {
+ lock (_scheduledActions) {
+ _scheduledActions.Add(new ScheduledAction(_physicsEnv[0].CurPhysicsFrameTime + (ulong)timeoutMs * 1000, action));
+ }
+ }
+
+ internal delegate void InputAction(ref PhysicsState state);
+
+ internal ref NativeParallelHashMap Balls => ref _ballStates;
+ internal ref InsideOfs InsideOfs => ref _insideOfs;
+ internal NativeQueue.ParallelWriter EventQueue => _eventQueue.AsParallelWriter();
+
+ internal void Schedule(InputAction action) => _inputActions.Enqueue(action);
+ internal ref BallState BallState(int ballId) => ref _ballStates.GetValueByRef(ballId);
+ internal ref BumperState BumperState(int itemId) => ref _bumperStates.GetValueByRef(itemId);
+ internal ref FlipperState FlipperState(int itemId) => ref _flipperStates.GetValueByRef(itemId);
+ internal ref GateState GateState(int itemId) => ref _gateStates.GetValueByRef(itemId);
+ internal ref DropTargetState DropTargetState(int itemId) => ref _dropTargetStates.GetValueByRef(itemId);
+ internal ref HitTargetState HitTargetState(int itemId) => ref _hitTargetStates.GetValueByRef(itemId);
+ internal ref KickerState KickerState(int itemId) => ref _kickerStates.GetValueByRef(itemId);
+ internal ref PlungerState PlungerState(int itemId) => ref _plungerStates.GetValueByRef(itemId);
+ internal ref SpinnerState SpinnerState(int itemId) => ref _spinnerStates.GetValueByRef(itemId);
+ internal ref SurfaceState SurfaceState(int itemId) => ref _surfaceStates.GetValueByRef(itemId);
+ internal ref TriggerState TriggerState(int itemId) => ref _triggerStates.GetValueByRef(itemId);
+ internal void SetBallInsideOf(int ballId, int itemId) => _insideOfs.SetInsideOf(itemId, ballId);
+ internal uint TimeMsec => _physicsEnv[0].TimeMsec;
+ internal void Register(T item) where T : MonoBehaviour
+ {
+ var go = item.gameObject;
+ var itemId = go.GetInstanceID();
+ _transforms.TryAdd(itemId, go.transform);
+
+ switch (item) {
+ case BallComponent c:
+ if (!_ballStates.ContainsKey(itemId)) {
+ _ballStates[itemId] = c.CreateState();
+ }
+ break;
+ case BumperComponent c: _bumperStates[itemId] = c.CreateState(); break;
+ case FlipperComponent c: _flipperStates[itemId] = c.CreateState(); break;
+ case GateComponent c: _gateStates[itemId] = c.CreateState(); break;
+ case DropTargetComponent c: _dropTargetStates[itemId] = c.CreateState(); break;
+ case HitTargetComponent c: _hitTargetStates[itemId] = c.CreateState(); break;
+ case KickerComponent c: _kickerStates[itemId] = c.CreateState(); break;
+ case PlungerComponent c:
+ _plungerStates[itemId] = c.CreateState();
+ _skinnedMeshRenderers[itemId] = c.GetComponentsInChildren();
+ break;
+ case SpinnerComponent c: _spinnerStates[itemId] = c.CreateState(); break;
+ case SurfaceComponent c: _surfaceStates[itemId] = c.CreateState(); break;
+ case TriggerComponent c: _triggerStates[itemId] = c.CreateState(); break;
+ }
+ }
+
+ internal Transform UnregisterBall(int ballId)
+ {
+ var transform = _transforms[ballId];
+ _transforms.Remove(ballId);
+ _ballStates.Remove(ballId);
+ return transform;
+ }
+
+ internal void EnableCollider(int itemId)
+ {
+ if (_disabledCollisionItems.Contains(itemId)) {
+ _disabledCollisionItems.Remove(itemId);
+ }
+ }
+ internal void DisableCollider(int itemId)
+ {
+ if (!_disabledCollisionItems.Contains(itemId)) {
+ _disabledCollisionItems.Add(itemId);
+ }
+ }
+
+ #endregion
+
+ #region Event Functions
+
+ private void Awake()
+ {
+ _player = GetComponentInParent();
+ _insideOfs = new InsideOfs(Allocator.Persistent);
+ _physicsEnv[0] = new PhysicsEnv(NowUsec, GetComponentInChildren(), GravityStrength);
+ }
+
+ private void Start()
+ {
+ // create static octree
+ var sw = Stopwatch.StartNew();
+ var colliderItems = GetComponentsInChildren();
+ Debug.Log($"Found {colliderItems.Length} collidable items.");
+ var colliders = new ColliderReference(Allocator.TempJob);
+ foreach (var colliderItem in colliderItems) {
+ if (!colliderItem.IsCollidable) {
+ _disabledCollisionItems.Add(colliderItem.ItemId);
+ }
+ colliderItem.GetColliders(_player, ref colliders, 0);
+ }
+
+ // allocate colliders
+ _colliders = new NativeColliders(ref colliders, Allocator.Persistent);
+
+ // create octree
+ var elapsedMs = sw.Elapsed.TotalMilliseconds;
+ var playfieldBounds = GetComponentInChildren().Bounds;
+ _playfieldBounds = GetComponentInChildren().Bounds;
+ _octree = new NativeOctree(playfieldBounds, 1024, 10, Allocator.Persistent);
+
+ sw.Restart();
+ var populateJob = new PhysicsPopulateJob {
+ Colliders = _colliders,
+ Octree = _octree,
+ };
+ populateJob.Run();
+ _octree = populateJob.Octree;
+ Debug.Log($"Octree of {_colliders.Length} constructed (colliders: {elapsedMs}ms, tree: {sw.Elapsed.TotalMilliseconds}ms).");
+
+ // get balls
+ var balls = GetComponentsInChildren();
+ foreach (var ball in balls) {
+ Register(ball);
+ }
+ }
+
+ private void Update()
+ {
+ // prepare job
+ var events = _eventQueue.AsParallelWriter();
+ var updatePhysics = new PhysicsUpdateJob {
+ InitialTimeUsec = NowUsec,
+ DeltaTimeMs = Time.deltaTime * 1000,
+ PhysicsEnv = _physicsEnv,
+ Octree = _octree,
+ Colliders = _colliders,
+ InsideOfs = _insideOfs,
+ Events = events,
+ Balls = _ballStates,
+ BumperStates = _bumperStates,
+ DropTargetStates = _dropTargetStates,
+ FlipperStates = _flipperStates,
+ GateStates = _gateStates,
+ HitTargetStates = _hitTargetStates,
+ KickerStates = _kickerStates,
+ PlungerStates = _plungerStates,
+ SpinnerStates = _spinnerStates,
+ SurfaceStates = _surfaceStates,
+ TriggerStates = _triggerStates,
+ DisabledCollisionItems = _disabledCollisionItems,
+ PlayfieldBounds = _playfieldBounds,
+ OverlappingColliders = new NativeParallelHashSet(0, Allocator.TempJob)
+ };
+
+ var env = _physicsEnv[0];
+ var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref events, ref _insideOfs, ref _ballStates,
+ ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates,
+ ref _hitTargetStates, ref _kickerStates, ref _plungerStates, ref _spinnerStates,
+ ref _surfaceStates, ref _triggerStates, ref _disabledCollisionItems, ref _swapBallCollisionHandling);
+
+ // process input
+ while (_inputActions.Count > 0) {
+ var action = _inputActions.Dequeue();
+ action(ref state);
+ }
+
+ // run physics loop
+ updatePhysics.Run();
+
+ // dequeue events
+ while (_eventQueue.TryDequeue(out var eventData)) {
+ _player.OnEvent(in eventData);
+ }
+
+ // process scheduled events from managed land
+ lock (_scheduledActions) {
+ for (var i = _scheduledActions.Count - 1; i >= 0; i--) {
+ if (_physicsEnv[0].CurPhysicsFrameTime > _scheduledActions[i].ScheduleAt) {
+ _scheduledActions[i].Action();
+ _scheduledActions.RemoveAt(i);
+ }
+ }
+ }
+
+ // retrieve updated data
+ _ballStates = updatePhysics.Balls;
+ _physicsEnv = updatePhysics.PhysicsEnv;
+ _flipperStates = updatePhysics.FlipperStates;
+
+ #region Movements
+
+ // balls
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var ball = ref enumerator.Current.Value;
+ BallMovementPhysics.Move(ball, _transforms[ball.Id]);
+ }
+ }
+
+ // flippers
+ using (var enumerator = _flipperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var flipperState = ref enumerator.Current.Value;
+ var flipperTransform = _transforms[enumerator.Current.Key];
+ flipperTransform.localRotation = quaternion.Euler(0, flipperState.Movement.Angle, 0);
+ }
+ }
+
+ // bumpers
+ using (var enumerator = _bumperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var bumperState = ref enumerator.Current.Value;
+ if (bumperState.SkirtItemId != 0) {
+ BumperTransform.UpdateSkirt(in bumperState.SkirtAnimation, _transforms[bumperState.SkirtItemId]);
+ }
+ if (bumperState.RingItemId != 0) {
+ BumperTransform.UpdateRing(bumperState.RingItemId, in bumperState.RingAnimation, _transforms[bumperState.RingItemId]);
+ }
+ }
+ }
+
+ // drop targets
+ using (var enumerator = _dropTargetStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var dropTargetState = ref enumerator.Current.Value;
+ var dropTargetTransform = _transforms[dropTargetState.AnimatedItemId];
+ var localPos = dropTargetTransform.localPosition;
+ dropTargetTransform.localPosition = new Vector3(
+ localPos.x,
+ Physics.ScaleToWorld(dropTargetState.Animation.ZOffset),
+ localPos.z
+ );
+ }
+ }
+
+ // hit targets
+ using (var enumerator = _hitTargetStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var hitTargetState = ref enumerator.Current.Value;
+ var hitTargetTransform = _transforms[hitTargetState.AnimatedItemId];
+ var localRot = hitTargetTransform.localEulerAngles;
+ hitTargetTransform.localEulerAngles = new Vector3(
+ hitTargetState.Animation.XRotation,
+ localRot.y,
+ localRot.z
+ );
+ }
+ }
+
+ // gates
+ using (var enumerator = _gateStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var gateState = ref enumerator.Current.Value;
+ var gateTransform = _transforms[gateState.WireItemId];
+ gateTransform.localRotation = quaternion.RotateX(-gateState.Movement.Angle);
+ }
+ }
+
+ // plungers
+ using (var enumerator = _plungerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var plungerState = ref enumerator.Current.Value;
+ foreach (var skinnedMeshRenderer in _skinnedMeshRenderers[enumerator.Current.Key]) {
+ skinnedMeshRenderer.SetBlendShapeWeight(0, plungerState.Animation.Position);
+ }
+ }
+ }
+
+ // spinners
+ using (var enumerator = _spinnerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var spinnerState = ref enumerator.Current.Value;
+ var spinnerTransform = _transforms[spinnerState.AnimationItemId];
+ spinnerTransform.localRotation = quaternion.RotateX(-spinnerState.Movement.Angle);
+ }
+ }
+
+ // triggers
+ using (var enumerator = _triggerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var triggerState = ref enumerator.Current.Value;
+ if (triggerState.AnimatedItemId == 0) {
+ continue;
+ }
+ var triggerTransform = _transforms[triggerState.AnimatedItemId];
+ TriggerTransform.Update(triggerState.AnimatedItemId, in triggerState.Movement, triggerTransform);
+ }
+ }
+
+ #endregion
+ }
+
+ private void OnDestroy()
+ {
+ _physicsEnv.Dispose();
+ _eventQueue.Dispose();
+ _ballStates.Dispose();
+ _colliders.Dispose();
+ _insideOfs.Dispose();
+ _octree.Dispose();
+ _bumperStates.Dispose();
+ _dropTargetStates.Dispose();
+ _flipperStates.Dispose();
+ _gateStates.Dispose();
+ _hitTargetStates.Dispose();
+ using (var enumerator = _kickerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ enumerator.Current.Value.Dispose();
+ }
+ }
+ _kickerStates.Dispose();
+ _plungerStates.Dispose();
+ _spinnerStates.Dispose();
+ _surfaceStates.Dispose();
+ using (var enumerator = _triggerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ enumerator.Current.Value.Dispose();
+ }
+ }
+ _triggerStates.Dispose();
+ _disabledCollisionItems.Dispose();
+ }
+
+ #endregion
+
+ private class ScheduledAction
+ {
+ public readonly ulong ScheduleAt;
+ public readonly Action Action;
+
+ public ScheduledAction(ulong scheduleAt, Action action)
+ {
+ ScheduleAt = scheduleAt;
+ Action = action;
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballAutomaticWorldBootstrap.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs.meta
similarity index 61%
rename from VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballAutomaticWorldBootstrap.cs.meta
rename to VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs.meta
index c6bcf44b8..eda51e10e 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballAutomaticWorldBootstrap.cs.meta
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs.meta
@@ -1,11 +1,11 @@
fileFormatVersion: 2
-guid: e9b4ba602429a4aadaa2d69d71d900a5
+guid: b80d5ee1d3ab4a109515ddcf56026d94
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
- icon: {instanceID: 0}
+ icon: {fileID: 2800000, guid: b8980903958b24841adb47db27c3344e, type: 3}
userData:
assetBundleName:
assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs
new file mode 100644
index 000000000..0d6d446bb
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs
@@ -0,0 +1,47 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using Unity.Mathematics;
+using VisualPinball.Engine.Common;
+using Random = Unity.Mathematics.Random;
+
+namespace VisualPinball.Unity
+{
+ public struct PhysicsEnv : IDisposable
+ {
+ public readonly float3 Gravity;
+ public readonly ulong StartTimeUsec;
+ public ulong CurPhysicsFrameTime;
+ public ulong NextPhysicsFrameTime;
+ public uint TimeMsec;
+
+ public Random Random;
+
+ public PhysicsEnv(ulong startTimeUsec, PlayfieldComponent playfield, float gravityStrength) : this()
+ {
+ StartTimeUsec = startTimeUsec;
+ CurPhysicsFrameTime = StartTimeUsec;
+ NextPhysicsFrameTime = StartTimeUsec + PhysicsConstants.PhysicsStepTime;
+ Random = new Random((uint)UnityEngine.Random.Range(1, 100000));
+ Gravity = playfield.PlayfieldGravity(gravityStrength);
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs.meta
new file mode 100644
index 000000000..565fdfea9
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEnv.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b915f496c6ce491ba0ed3143007a1fe8
+timeCreated: 1678661883
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs
new file mode 100644
index 000000000..eaa43a57e
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs
@@ -0,0 +1,22 @@
+using NativeTrees;
+using Unity.Burst;
+using Unity.Collections;
+using Unity.Jobs;
+
+namespace VisualPinball.Unity
+{
+ [BurstCompile(CompileSynchronously = true)]
+ internal struct PhysicsPopulateJob : IJob
+ {
+ [ReadOnly]
+ public NativeColliders Colliders;
+ public NativeOctree Octree;
+
+ public void Execute()
+ {
+ for (var i = 0; i < Colliders.Length; i++) {
+ Octree.Insert(i, Colliders.GetAabb(i));
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs.meta
new file mode 100644
index 000000000..97f223edf
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsPopulateJob.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0d5b69cfa7a94e9885f48041fcd5af9a
+timeCreated: 1697223597
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs
new file mode 100644
index 000000000..996d8072f
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs
@@ -0,0 +1,187 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using NativeTrees;
+using Unity.Collections;
+using VisualPinball.Engine.VPT;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ internal struct PhysicsState
+ {
+ internal PhysicsEnv Env;
+ internal NativeOctree Octree;
+ internal NativeColliders Colliders;
+ internal NativeQueue.ParallelWriter EventQueue;
+ internal InsideOfs InsideOfs;
+ internal NativeParallelHashMap Balls;
+ internal NativeParallelHashMap BumperStates;
+ internal NativeParallelHashMap DropTargetStates;
+ internal NativeParallelHashMap FlipperStates;
+ internal NativeParallelHashMap GateStates;
+ internal NativeParallelHashMap HitTargetStates;
+ internal NativeParallelHashMap KickerStates;
+ internal NativeParallelHashMap PlungerStates;
+ internal NativeParallelHashMap SpinnerStates;
+ internal NativeParallelHashMap SurfaceStates;
+ internal NativeParallelHashMap TriggerStates;
+ internal NativeParallelHashSet DisabledCollisionItems;
+ internal bool SwapBallCollisionHandling;
+
+ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders,
+ ref NativeQueue.ParallelWriter eventQueue, ref InsideOfs insideOfs, ref NativeParallelHashMap balls,
+ ref NativeParallelHashMap bumperStates, ref NativeParallelHashMap dropTargetStates,
+ ref NativeParallelHashMap flipperStates, ref NativeParallelHashMap gateStates,
+ ref NativeParallelHashMap hitTargetStates, ref NativeParallelHashMap kickerStates,
+ ref NativeParallelHashMap plungerStates, ref NativeParallelHashMap spinnerStates,
+ ref NativeParallelHashMap surfaceStates, ref NativeParallelHashMap triggerStates,
+ ref NativeParallelHashSet disabledCollisionItems, ref bool swapBallCollisionHandling)
+ {
+ Env = env;
+ Octree = octree;
+ Colliders = colliders;
+ EventQueue = eventQueue;
+ InsideOfs = insideOfs;
+ Balls = balls;
+ BumperStates = bumperStates;
+ DropTargetStates = dropTargetStates;
+ FlipperStates = flipperStates;
+ GateStates = gateStates;
+ HitTargetStates = hitTargetStates;
+ KickerStates = kickerStates;
+ PlungerStates = plungerStates;
+ SpinnerStates = spinnerStates;
+ SurfaceStates = surfaceStates;
+ TriggerStates = triggerStates;
+ DisabledCollisionItems = disabledCollisionItems;
+ SwapBallCollisionHandling = swapBallCollisionHandling;
+ }
+
+ internal ref ColliderHeader GetColliderHeader(int colliderId) => ref Colliders.GetHeader(colliderId);
+ internal ColliderType GetColliderType(int colliderId) => Colliders.GetHeader(colliderId).Type;
+
+ internal bool IsColliderActive(int colliderId) => !DisabledCollisionItems.Contains(Colliders.GetItemId(colliderId));
+
+ #region States
+
+ internal ref FlipperState GetFlipperState(int colliderId) => ref FlipperStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref PlungerState GetPlungerState(int colliderId) => ref PlungerStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref SpinnerState GetSpinnerState(int colliderId) => ref SpinnerStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref TriggerState GetTriggerState(int colliderId) => ref TriggerStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref KickerState GetKickerState(int colliderId) => ref KickerStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+
+ internal bool HasDropTargetState(int colliderId) => DropTargetStates.ContainsKey(Colliders.GetItemId(colliderId));
+
+ internal bool HasHitTargetState(int colliderId) => HitTargetStates.ContainsKey(Colliders.GetItemId(colliderId));
+
+ internal ref DropTargetState GetDropTargetState(int colliderId) => ref DropTargetStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref HitTargetState GetHitTargetState(int colliderId) => ref HitTargetStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref BumperState GetBumperState(int colliderId) => ref BumperStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref GateState GetGateState(int colliderId) => ref GateStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ internal ref SurfaceState GetSurfaceState(int colliderId) => ref SurfaceStates.GetValueByRef(Colliders.GetItemId(colliderId));
+
+ #endregion
+
+ #region Hit Test
+
+ internal float HitTest(int colliderId, ref BallState ball, ref CollisionEventData collEvent, ref NativeList contacts, ref PhysicsState state)
+ {
+ if (IsInactiveDropTarget(colliderId)) {
+ return -1f;
+ }
+ switch (GetColliderType(colliderId)) {
+ case ColliderType.Bumper:
+ case ColliderType.Circle:
+ return Colliders.Circle(colliderId).HitTest(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime);
+
+ case ColliderType.Gate:
+ return Colliders.Gate(colliderId).HitTest(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime);
+
+ case ColliderType.Line:
+ return Colliders.Line(colliderId).HitTest(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime);
+
+ case ColliderType.LineZ:
+ return Colliders.LineZ(colliderId).HitTest(ref collEvent, in ball, ball.CollisionEvent.HitTime);
+
+ case ColliderType.Line3D:
+ return Colliders.Line3D(colliderId).HitTest(ref collEvent, in ball, ball.CollisionEvent.HitTime);
+
+ case ColliderType.LineSlingShot:
+ return Colliders.LineSlingShot(colliderId).HitTest(ref collEvent, ref state.InsideOfs, in ball, ball.CollisionEvent.HitTime);
+
+ case ColliderType.Point:
+ return Colliders.Point(colliderId).HitTest(ref collEvent, in ball, ball.CollisionEvent.HitTime);
+
+ case ColliderType.Plane:
+ return Colliders.Plane(colliderId).HitTest(ref collEvent, in ball, ball.CollisionEvent.HitTime);
+
+ case ColliderType.Spinner:
+ return Colliders.Spinner(colliderId).HitTest(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime);
+
+ case ColliderType.Triangle:
+ return Colliders.Triangle(colliderId).HitTest(ref collEvent, in state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime);
+
+ case ColliderType.KickerCircle:
+ case ColliderType.TriggerCircle:
+ return Colliders.Circle(colliderId).HitTestBasicRadius(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime, false, false, false);
+
+ case ColliderType.TriggerLine:
+ return Colliders.Line(colliderId).HitTestBasic(ref collEvent, ref state.InsideOfs, in ball,
+ ball.CollisionEvent.HitTime, false, false, false);
+
+ case ColliderType.Flipper:
+ ref var flipperState = ref state.GetFlipperState(colliderId);
+ return Colliders.Flipper(colliderId).HitTest(ref collEvent, ref state.InsideOfs, ref flipperState.Hit,
+ in flipperState.Movement, in flipperState.Tricks, in flipperState.Static, in ball, collEvent.HitTime);
+
+ case ColliderType.Plunger:
+ ref var plungerState = ref state.GetPlungerState(colliderId);
+ return Colliders.Plunger(colliderId).HitTest(ref collEvent, ref state.InsideOfs, ref plungerState.Movement,
+ in plungerState.Collider, in plungerState.Static, in ball, collEvent.HitTime);
+ }
+ return -1f;
+ }
+
+ private bool IsInactiveDropTarget(int colliderId)
+ {
+ if (Colliders.GetItemType(colliderId) == ItemType.HitTarget && HasDropTargetState(colliderId)) {
+ ref var dropTargetState = ref GetDropTargetState(colliderId);
+ if (dropTargetState.Animation.IsDropped || dropTargetState.Animation.MoveAnimation) { // QUICKFIX so that DT is not triggered twice
+ return true;
+ }
+ }
+ return false;
+ }
+
+ #endregion
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs.meta
new file mode 100644
index 000000000..075d404dc
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5f6509a9a6e74f81a4c439f5c2f4a2d2
+timeCreated: 1696276234
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs
new file mode 100644
index 000000000..2e7d7dcdf
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs
@@ -0,0 +1,35 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using NativeTrees;
+using Unity.Collections;
+using Unity.Profiling;
+
+namespace VisualPinball.Unity
+{
+ public static class PhysicsStaticBroadPhase
+ {
+ private static readonly ProfilerMarker PerfMarkerBroadPhase = new("BroadPhase");
+
+ internal static void FindOverlaps(in NativeOctree octree, in BallState ball, ref NativeParallelHashSet overlappingColliders)
+ {
+ PerfMarkerBroadPhase.Begin();
+ overlappingColliders.Clear();
+ octree.RangeAABBUnique(ball.Aabb, overlappingColliders);
+ PerfMarkerBroadPhase.End();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs.meta
new file mode 100644
index 000000000..7b50c62e2
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticBroadPhase.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0cf814a76e55460fb3a3232176ead728
+timeCreated: 1678825180
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs
new file mode 100644
index 000000000..1fa4ae3e7
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs
@@ -0,0 +1,178 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// ReSharper disable ConvertIfStatementToSwitchStatement
+
+using VisualPinball.Engine.VPT;
+using VisualPinball.Unity.Collections;
+
+namespace VisualPinball.Unity
+{
+ internal static class PhysicsStaticCollision
+ {
+ internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState state)
+ {
+
+ // find balls with hit objects and minimum time
+ if (ball.CollisionEvent.ColliderId < 0 || ball.CollisionEvent.HitTime > hitTime) {
+ return;
+ }
+
+ Collide(ref ball, ref state);
+
+ // remove trial hit object pointer
+ ball.CollisionEvent.ClearCollider();
+ }
+
+ private static void Collide(ref BallState ball, ref PhysicsState state)
+ {
+ var colliderId = ball.CollisionEvent.ColliderId;
+ var collHeader = state.GetColliderHeader(colliderId);
+ if (CollidesWithItem(ref collHeader, ref ball, ref state)) {
+ return;
+ }
+ ref var cols = ref state.Colliders;
+ switch (state.GetColliderType(colliderId)) {
+
+ case ColliderType.Circle:
+ ref var circleCollider = ref cols.Circle(colliderId);
+ circleCollider.Collide(ref ball, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Plane:
+ ref var planeCollider = ref cols.Plane(colliderId);
+ planeCollider.Collide(ref ball, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Line:
+ ref var lineCollider = ref cols.Line(colliderId);
+ lineCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Triangle:
+ ref var triangleCollider = ref cols.Triangle(colliderId);
+ triangleCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Line3D:
+ ref var line3DCollider = ref cols.Line3D(colliderId);
+ line3DCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Point:
+ ref var pointCollider = ref cols.Point(colliderId);
+ pointCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Bumper:
+ ref var bumperState = ref state.GetBumperState(colliderId);
+ BumperCollider.Collide(ref ball, ref state.EventQueue, ref ball.CollisionEvent, ref bumperState.RingAnimation, ref bumperState.SkirtAnimation,
+ in collHeader, in bumperState.Static, ref state.Env.Random);
+ break;
+
+ case ColliderType.Flipper:
+ ref var flipperState = ref state.GetFlipperState(colliderId);
+ ref var flipperCollider = ref cols.Flipper(colliderId);
+ flipperCollider.Collide(ref ball, ref ball.CollisionEvent, ref flipperState.Movement,
+ ref state.EventQueue, in ball.Id, in flipperState.Tricks, in flipperState.Static,
+ in flipperState.Velocity, in flipperState.Hit, state.Env.TimeMsec
+ );
+ break;
+
+ case ColliderType.Gate:
+ ref var gateState = ref state.GetGateState(colliderId);
+ GateCollider.Collide(ref ball, ref ball.CollisionEvent, ref gateState.Movement, ref state.EventQueue,
+ in collHeader, in gateState.Static);
+ break;
+
+ case ColliderType.LineSlingShot:
+ ref var surfaceState = ref state.GetSurfaceState(colliderId);
+ ref var surfaceCollider = ref cols.LineSlingShot(colliderId);
+ surfaceCollider.Collide(ref ball, ref state.EventQueue, in surfaceState.Slingshot,
+ in ball.CollisionEvent, ref state.Env.Random);
+ break;
+
+ case ColliderType.Plunger:
+ ref var plungerState = ref state.GetPlungerState(colliderId);
+ PlungerCollider.Collide(ref ball, ref ball.CollisionEvent, ref plungerState.Movement, in plungerState.Static, ref state.Env.Random);
+ break;
+
+ case ColliderType.Spinner:
+ ref var spinnerState = ref state.GetSpinnerState(colliderId);
+ SpinnerCollider.Collide(in ball, ref ball.CollisionEvent, ref spinnerState.Movement, in spinnerState.Static);
+ break;
+
+ case ColliderType.TriggerCircle:
+ case ColliderType.TriggerLine:
+ TriggerCollide(ref ball, ref state, in collHeader);
+ break;
+
+ case ColliderType.KickerCircle:
+ ref var kickerState = ref state.GetKickerState(colliderId);
+ KickerCollider.Collide(ref ball, ref state.EventQueue, ref state.InsideOfs, ref kickerState.Collision,
+ in kickerState.Static, in kickerState.CollisionMesh, in ball.CollisionEvent, collHeader.ItemId, false);
+ break;
+ }
+ }
+
+ private static bool CollidesWithItem(ref ColliderHeader collHeader, ref BallState ball, ref PhysicsState state)
+ {
+ ref var cols = ref state.Colliders;
+
+ // hit target
+ var colliderId = ball.CollisionEvent.ColliderId;
+ if (collHeader.ItemType == ItemType.HitTarget) {
+
+ var normal = collHeader.Type == ColliderType.Triangle
+ ? cols.Triangle(colliderId).Normal()
+ : ball.CollisionEvent.HitNormal;
+
+ if (state.HasDropTargetState(colliderId)) {
+ ref var dropTargetState = ref state.GetDropTargetState(colliderId);
+ TargetCollider.DropTargetCollide(ref ball, ref state.EventQueue, ref dropTargetState.Animation, in normal, in ball.CollisionEvent, in collHeader, ref state.Env.Random);
+ return true;
+ }
+
+ if (state.HasHitTargetState(colliderId)) {
+ ref var hitTargetState = ref state.GetHitTargetState(colliderId);
+ TargetCollider.HitTargetCollide(ref ball, ref state.EventQueue, ref hitTargetState.Animation, in normal, in ball.CollisionEvent, in collHeader, ref state.Env.Random);
+ return true;
+ }
+
+ // trigger
+ } else if (collHeader.ItemType == ItemType.Trigger) {
+ TriggerCollide(ref ball, ref state, in collHeader);
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void TriggerCollide(ref BallState ball, ref PhysicsState state, in ColliderHeader collHeader)
+ {
+ ref var triggerState = ref state.GetTriggerState(collHeader.Id);
+ TriggerCollider.Collide(ref ball, ref state.EventQueue, ref ball.CollisionEvent, ref state.InsideOfs, ref triggerState.Animation, in collHeader);
+
+ if (triggerState.FlipperCorrection.IsEnabled) {
+ if (triggerState.Animation.UnHitEvent) {
+ ref var flipperCorrectionState = ref triggerState.FlipperCorrection;
+ ref var fs = ref state.FlipperStates.GetValueByRef(flipperCorrectionState.FlipperItemId);
+ FlipperCorrection.OnBallLeaveFlipper(ref ball, ref flipperCorrectionState, in fs.Movement, in fs.Tricks, in fs.Static, state.Env.TimeMsec);
+ }
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs.meta
new file mode 100644
index 000000000..de996f8c7
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: af1a4f63b59246f2be6138582acfa192
+timeCreated: 1679007108
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs
new file mode 100644
index 000000000..246dd1f8b
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs
@@ -0,0 +1,77 @@
+// Visual Pinball Engine
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// ReSharper disable ForCanBeConvertedToForeach
+
+using Unity.Collections;
+using Unity.Profiling;
+
+namespace VisualPinball.Unity
+{
+ public static class PhysicsStaticNarrowPhase
+ {
+ private static readonly ProfilerMarker PerfMarkerNarrowPhase = new("NarrowPhase");
+
+ internal static void FindNextCollision(
+ float hitTime,
+ ref BallState ball,
+ ref NativeParallelHashSet overlappingColliders,
+ ref NativeList contacts,
+ ref PhysicsState state
+ )
+ {
+ PerfMarkerNarrowPhase.Begin();
+
+ // init contacts and event
+ ball.CollisionEvent.ClearCollider(hitTime); // search upto current hit time
+
+ using (var enumerator = overlappingColliders.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ var overlappingColliderId = enumerator.Current;
+ if (!state.IsColliderActive(overlappingColliderId)) {
+ continue;
+ }
+ var newCollEvent = new CollisionEventData();
+ var newTime = state.HitTest(overlappingColliderId, ref ball, ref newCollEvent, ref contacts, ref state);
+ SaveCollisions(ref ball, ref newCollEvent, ref contacts, overlappingColliderId, newTime);
+ }
+ }
+
+ // no negative time allowed
+ if (ball.CollisionEvent.HitTime < 0) {
+ ball.CollisionEvent.ClearCollider();
+ }
+ PerfMarkerNarrowPhase.End();
+ }
+
+ private static void SaveCollisions(ref BallState ball, ref CollisionEventData newCollEvent,
+ ref NativeList contacts, int colliderId, float newTime)
+ {
+ var validHit = newTime >= 0f && !Math.Sign(newTime) && newTime <= ball.CollisionEvent.HitTime;
+
+ if (newCollEvent.IsContact || validHit) { // todo why newCollEvent.IsContact? it's not in vpx source
+ newCollEvent.SetCollider(colliderId);
+ newCollEvent.HitTime = newTime;
+ if (newCollEvent.IsContact) { // remember all contacts?
+ contacts.Add(new ContactBufferElement(ball.Id, newCollEvent));
+
+ } else { // if (validhit)
+ ball.CollisionEvent = newCollEvent;
+ }
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs.meta
new file mode 100644
index 000000000..7d1b87346
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a04a4f7580b94ee6af69ff781069ce5f
+timeCreated: 1678831337
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs
new file mode 100644
index 000000000..f247a812c
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs
@@ -0,0 +1,175 @@
+// Copyright (C) 2023 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using NativeTrees;
+using Unity.Burst;
+using Unity.Collections;
+using Unity.Jobs;
+using VisualPinball.Engine.Common;
+
+namespace VisualPinball.Unity
+{
+ [BurstCompile(CompileSynchronously = true)]
+ internal struct PhysicsUpdateJob : IJob
+ {
+ [ReadOnly]
+ public ulong InitialTimeUsec;
+
+ public float DeltaTimeMs;
+
+ [NativeDisableParallelForRestriction]
+ public NativeParallelHashSet OverlappingColliders;
+ public NativeArray PhysicsEnv;
+ public NativeOctree Octree;
+ public NativeColliders Colliders;
+ public InsideOfs InsideOfs;
+ public NativeQueue.ParallelWriter Events;
+ public AABB PlayfieldBounds;
+
+ public NativeParallelHashMap Balls;
+ public NativeParallelHashMap BumperStates;
+ public NativeParallelHashMap DropTargetStates;
+ public NativeParallelHashMap FlipperStates;
+ public NativeParallelHashMap GateStates;
+ public NativeParallelHashMap HitTargetStates;
+ public NativeParallelHashMap KickerStates;
+ public NativeParallelHashMap PlungerStates;
+ public NativeParallelHashMap SpinnerStates;
+ public NativeParallelHashMap SurfaceStates;
+ public NativeParallelHashMap TriggerStates;
+ public NativeParallelHashSet DisabledCollisionItems;
+ public bool SwapBallCollisionHandling;
+
+ public void Execute()
+ {
+ var env = PhysicsEnv[0];
+ var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref Events, ref InsideOfs, ref Balls,
+ ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates,
+ ref HitTargetStates, ref KickerStates, ref PlungerStates, ref SpinnerStates,
+ ref SurfaceStates, ref TriggerStates, ref DisabledCollisionItems, ref SwapBallCollisionHandling);
+ var cycle = new PhysicsCycle(Allocator.Temp);
+
+ while (env.CurPhysicsFrameTime < InitialTimeUsec) // loop here until current (real) time matches the physics (simulated) time
+ {
+ env.TimeMsec = (uint)((env.CurPhysicsFrameTime - env.StartTimeUsec) / 1000);
+ var physicsDiffTime = (float)((env.NextPhysicsFrameTime - env.CurPhysicsFrameTime) * (1.0 / PhysicsConstants.DefaultStepTime));
+
+ // update velocities - always on integral physics frame boundary (spinner, gate, flipper, plunger, ball)
+ #region Update Velocities
+
+ // balls
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ BallVelocityPhysics.UpdateVelocities(ref enumerator.Current.Value, env.Gravity);
+ }
+ }
+ // flippers
+ using (var enumerator = FlipperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ FlipperVelocityPhysics.UpdateVelocities(ref enumerator.Current.Value);
+ }
+ }
+ // gates
+ using (var enumerator = GateStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var gateState = ref enumerator.Current.Value;
+ GateVelocityPhysics.UpdateVelocities(ref gateState.Movement, in gateState.Static);
+ }
+ }
+ // plungers
+ using (var enumerator = PlungerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var plungerState = ref enumerator.Current.Value;
+ PlungerVelocityPhysics.UpdateVelocities(ref plungerState.Movement, ref plungerState.Velocity, in plungerState.Static);
+ }
+ }
+ // spinners
+ using (var enumerator = SpinnerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var spinnerState = ref enumerator.Current.Value;
+ SpinnerVelocityPhysics.UpdateVelocities(ref spinnerState.Movement, in spinnerState.Static);
+ }
+ }
+
+ #endregion
+
+ // primary physics loop
+ cycle.Simulate(ref state, in PlayfieldBounds, ref OverlappingColliders, physicsDiffTime);
+
+ // ball trail, keep old pos of balls
+ using (var enumerator = state.Balls.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ BallRingCounterPhysics.Update(ref enumerator.Current.Value);
+ }
+ }
+
+ #region Animation
+
+ // bumper
+ using (var enumerator = BumperStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var bumperState = ref enumerator.Current.Value;
+ if (bumperState.RingItemId != 0) {
+ BumperRingAnimation.Update(ref bumperState.RingAnimation, DeltaTimeMs);
+ }
+ if (bumperState.SkirtItemId != 0) {
+ BumperSkirtAnimation.Update(ref bumperState.SkirtAnimation, DeltaTimeMs);
+ }
+ }
+ }
+
+ // drop target
+ using (var enumerator = DropTargetStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var dropTargetState = ref enumerator.Current.Value;
+ DropTargetAnimation.Update(enumerator.Current.Key, ref dropTargetState.Animation, in dropTargetState.Static, ref state);
+ }
+ }
+
+ // hit target
+ using (var enumerator = HitTargetStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var hitTargetState = ref enumerator.Current.Value;
+ HitTargetAnimation.Update(ref hitTargetState.Animation, in hitTargetState.Static, env.TimeMsec);
+ }
+ }
+
+ // plunger
+ using (var enumerator = PlungerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var plungerState = ref enumerator.Current.Value;
+ PlungerAnimation.Update(ref plungerState.Animation, in plungerState.Movement, in plungerState.Static);
+ }
+ }
+
+ // trigger
+ using (var enumerator = TriggerStates.GetEnumerator()) {
+ while (enumerator.MoveNext()) {
+ ref var triggerState = ref enumerator.Current.Value;
+ TriggerAnimation.Update(ref triggerState.Animation, ref triggerState.Movement, in triggerState.Static, DeltaTimeMs);
+ }
+ }
+
+ #endregion
+
+ env.CurPhysicsFrameTime = env.NextPhysicsFrameTime;
+ env.NextPhysicsFrameTime += PhysicsConstants.PhysicsStepTime;
+ }
+
+ PhysicsEnv[0] = env;
+ cycle.Dispose();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs.meta
new file mode 100644
index 000000000..2817b063a
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0b10767332f9444e84e5c9293196e58a
+timeCreated: 1697223526
\ No newline at end of file
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
index 47d088618..d197481f3 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
@@ -18,14 +18,13 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
-using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
using VisualPinball.Engine.Common;
using VisualPinball.Engine.Game;
using VisualPinball.Engine.Game.Engines;
-using VisualPinball.Engine.VPT.Trigger;
+using Color = VisualPinball.Engine.Math.Color;
using Logger = NLog.Logger;
namespace VisualPinball.Unity
@@ -36,7 +35,7 @@ public class Player : MonoBehaviour
public PlayfieldApi PlayfieldApi { get; private set; }
// shortcuts
- public GameObject Playfield => _playfieldComponent.gameObject;
+ public GameObject Playfield => PlayfieldComponent.gameObject;
[NonSerialized]
public IGamelogicEngine GamelogicEngine;
@@ -44,7 +43,7 @@ public class Player : MonoBehaviour
[NonSerialized]
public BallManager BallManager;
- public event EventHandler OnPlayerStarted;
+ public event EventHandler OnPlayeStarted;
public List SwitchMapping => _tableComponent.MappingConfig.Switches;
public List CoilMapping => _tableComponent.MappingConfig.Coils;
@@ -56,45 +55,32 @@ public class Player : MonoBehaviour
public event EventHandler OnBallDestroyed;
[HideInInspector] [SerializeField] public string debugUiId;
- [HideInInspector] [SerializeField] public string physicsEngineId;
[Tooltip("When enabled, update the switch, coil, lamp and wire manager windows in the editor (slower performance)")]
public bool UpdateDuringGamplay = true;
// table related
- private readonly List _apis = new List();
- private readonly List _colliderGenerators = new List();
- private readonly Dictionary _hittables = new Dictionary();
- private readonly Dictionary _rotatables = new Dictionary();
- private readonly Dictionary _collidables = new Dictionary();
- private readonly Dictionary _spinnables = new Dictionary();
- private readonly Dictionary _slingshots = new Dictionary();
- private readonly Dictionary _droppables = new Dictionary();
-
- internal readonly Dictionary FlipperTransforms = new Dictionary();
- internal readonly Dictionary BumperSkirtTransforms = new Dictionary();
- internal readonly Dictionary BumperRingTransforms = new Dictionary();
- internal readonly Dictionary GateWireTransforms = new Dictionary();
- internal readonly Dictionary HitTargetTransforms = new Dictionary();
- internal readonly Dictionary DropTargetTransforms = new Dictionary();
- internal readonly Dictionary SpinnerPlateTransforms = new Dictionary();
- internal readonly Dictionary TriggerTransforms = new Dictionary();
- internal readonly Dictionary PlungerSkinnedMeshRenderers = new Dictionary();
- internal readonly Dictionary Balls = new Dictionary();
+ private readonly List _apis = new();
+ private readonly List _colliderGenerators = new();
+ private readonly Dictionary _hittables = new();
+ private readonly Dictionary _rotatables = new();
+ private readonly Dictionary _collidables = new();
+ private readonly Dictionary _spinnables = new();
+ private readonly Dictionary _slingshots = new();
+ private readonly Dictionary _droppables = new();
internal IEnumerable ColliderGenerators => _colliderGenerators;
// input related
[NonSerialized] private InputManager _inputManager;
- [NonSerialized] private VisualPinballSimulationSystemGroup _simulationSystemGroup;
- [NonSerialized] private readonly List<(InputAction, Action)> _actions = new List<(InputAction, Action)>();
+ [NonSerialized] private readonly List<(InputAction, Action)> _actions = new();
// players
- [NonSerialized] private readonly LampPlayer _lampPlayer = new LampPlayer();
- [NonSerialized] private readonly CoilPlayer _coilPlayer = new CoilPlayer();
- [NonSerialized] private readonly SwitchPlayer _switchPlayer = new SwitchPlayer();
- [NonSerialized] private readonly WirePlayer _wirePlayer = new WirePlayer();
- [NonSerialized] private readonly DisplayPlayer _displayPlayer = new DisplayPlayer();
+ [NonSerialized] private readonly LampPlayer _lampPlayer = new();
+ [NonSerialized] private readonly CoilPlayer _coilPlayer = new();
+ [NonSerialized] private readonly SwitchPlayer _switchPlayer = new();
+ [NonSerialized] private readonly WirePlayer _wirePlayer = new();
+ [NonSerialized] private readonly DisplayPlayer _displayPlayer = new();
private const float SlowMotionMax = 0.1f;
private const float TimeLapseMax = 2.5f;
@@ -102,8 +88,25 @@ public class Player : MonoBehaviour
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private TableComponent _tableComponent;
private PlayfieldComponent _playfieldComponent;
+ private PhysicsEngine _physicsEngine;
- internal static readonly Entity PlayfieldEntity = new Entity {Index = -3, Version = 0}; // a fake entity we just use for reference
+ private PlayfieldComponent PlayfieldComponent {
+ get {
+ if (_playfieldComponent == null) {
+ _playfieldComponent = GetComponentInChildren();
+ }
+ return _playfieldComponent;
+ }
+ }
+
+ private PhysicsEngine PhysicsEngine {
+ get {
+ if (_physicsEngine == null) {
+ _physicsEngine = GetComponentInChildren();
+ }
+ return _physicsEngine;
+ }
+ }
#region Access
@@ -117,11 +120,13 @@ public class Player : MonoBehaviour
public Dictionary CoilStatuses => _coilPlayer.CoilStatuses;
public Dictionary LampStatuses => _lampPlayer.LampStates;
public Dictionary WireStatuses => _wirePlayer.WireStatuses;
- public float3 Gravity => _playfieldComponent.Gravity;
+
+ public int NextBallId => ++_currentBallId;
+ private int _currentBallId;
public void SetLamp(string lampId, float value) => _lampPlayer.HandleLampEvent(lampId, value);
public void SetLamp(string lampId, LampStatus status) => _lampPlayer.HandleLampEvent(lampId, status);
- public void SetLamp(string lampId, VisualPinball.Engine.Math.Color color) => _lampPlayer.HandleLampEvent(lampId, color);
+ public void SetLamp(string lampId, Color color) => _lampPlayer.HandleLampEvent(lampId, color);
#endregion
@@ -135,12 +140,11 @@ public Player()
private void Awake()
{
_tableComponent = GetComponent();
- _playfieldComponent = GetComponentInChildren();
var engineComponent = GetComponent();
_apis.Add(TableApi);
- BallManager = new BallManager(this);
+ BallManager = new BallManager(GetComponentInChildren(), this, Playfield.transform);
_inputManager = new InputManager();
_inputManager.Enable(HandleInput);
@@ -149,16 +153,9 @@ private void Awake()
_lampPlayer.Awake(this, _tableComponent, GamelogicEngine);
_coilPlayer.Awake(this, _tableComponent, GamelogicEngine, _lampPlayer, _wirePlayer);
_switchPlayer.Awake(_tableComponent, GamelogicEngine, _inputManager);
- _wirePlayer.Awake(_tableComponent, _inputManager, _switchPlayer, this);
+ _wirePlayer.Awake(_tableComponent, _inputManager, _switchPlayer, this, PhysicsEngine);
_displayPlayer.Awake(GamelogicEngine);
}
-
- EngineProvider.Set(physicsEngineId);
- EngineProvider