diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index db11adc07f..4509b3783b 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -144,7 +144,7 @@ jobs:
           dev-install: true
           update: true
       - name: Export API Documentation
-        run: invoke schema --ignore-warnings
+        run: invoke schema --ignore-warnings --filename InvenTree/schema.yml
       - name: Upload schema
         uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # pin@v3.1.3
         with:
@@ -160,7 +160,7 @@ jobs:
           echo "URL: $url"
           curl -s -o api.yaml $url
           echo "Downloaded api.yaml"
-      - name: Check for differences in schemas
+      - name: Check for differences in API Schema
         if: needs.paths-filter.outputs.api == 'false'
         run: |
           diff --color -u InvenTree/schema.yml api.yaml
diff --git a/.gitignore b/.gitignore
index 5f2b31d170..bcc2f2ac5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,3 +104,7 @@ api.yaml
 
 # web frontend (static files)
 InvenTree/web/static
+
+# Generated docs files
+docs/docs/api/*.yml
+docs/docs/api/schema/*.yml
diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py
index c99f1d2faf..28e10bde2c 100644
--- a/InvenTree/InvenTree/api_version.py
+++ b/InvenTree/InvenTree/api_version.py
@@ -1,11 +1,14 @@
 """InvenTree API version information."""
 
 # InvenTree API version
-INVENTREE_API_VERSION = 179
+INVENTREE_API_VERSION = 180
 """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
 
 INVENTREE_API_TEXT = """
 
+v180 - 2024-3-02 : https://github.com/inventree/InvenTree/pull/6463
+    - Tweaks to API documentation to allow automatic documentation generation
+
 v179 - 2024-03-01 : https://github.com/inventree/InvenTree/pull/6605
     - Adds "subcategories" count to PartCategory serializer
     - Adds "sublocations" count to StockLocation serializer
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index f08b85e2e7..83947e6d52 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -469,21 +469,6 @@ if USE_JWT:
     INSTALLED_APPS.append('rest_framework_simplejwt')
 
 # WSGI default setting
-SPECTACULAR_SETTINGS = {
-    'TITLE': 'InvenTree API',
-    'DESCRIPTION': 'API for InvenTree - the intuitive open source inventory management system',
-    'LICENSE': {
-        'name': 'MIT',
-        'url': 'https://github.com/inventree/InvenTree/blob/master/LICENSE',
-    },
-    'EXTERNAL_DOCS': {
-        'description': 'More information about InvenTree in the official docs',
-        'url': 'https://docs.inventree.org',
-    },
-    'VERSION': str(inventreeApiVersion()),
-    'SERVE_INCLUDE_SCHEMA': False,
-}
-
 WSGI_APPLICATION = 'InvenTree.wsgi.application'
 
 """
@@ -1208,3 +1193,23 @@ if CUSTOM_FLAGS:
 # Magic login django-sesame
 SESAME_MAX_AGE = 300
 LOGIN_REDIRECT_URL = '/api/auth/login-redirect/'
+
+# Configuratino for API schema generation
+SPECTACULAR_SETTINGS = {
+    'TITLE': 'InvenTree API',
+    'DESCRIPTION': 'API for InvenTree - the intuitive open source inventory management system',
+    'LICENSE': {
+        'name': 'MIT',
+        'url': 'https://github.com/inventree/InvenTree/blob/master/LICENSE',
+    },
+    'EXTERNAL_DOCS': {
+        'description': 'More information about InvenTree in the official docs',
+        'url': 'https://docs.inventree.org',
+    },
+    'VERSION': str(inventreeApiVersion()),
+    'SERVE_INCLUDE_SCHEMA': False,
+    'SCHEMA_PATH_PREFIX': '/api/',
+}
+
+if SITE_URL:
+    SPECTACULAR_SETTINGS['SERVERS'] = [{'url': SITE_URL}]
diff --git a/InvenTree/machine/api.py b/InvenTree/machine/api.py
index 9448d2ea99..3bd2853467 100644
--- a/InvenTree/machine/api.py
+++ b/InvenTree/machine/api.py
@@ -144,7 +144,9 @@ class MachineRestart(APIView):
 
     permission_classes = [permissions.IsAuthenticated]
 
-    @extend_schema(responses={200: MachineSerializers.MachineRestartSerializer()})
+    @extend_schema(
+        request=None, responses={200: MachineSerializers.MachineRestartSerializer()}
+    )
     def post(self, request, pk):
         """Restart machine by pk."""
         machine = get_machine(pk)
diff --git a/docs/.gitignore b/docs/.gitignore
index ecbeb1b0ab..ea8649cfa3 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -10,6 +10,9 @@ env/
 _build/
 site/
 
+# Generated API schema files
+docs/api/schema/*.yml
+
 # Temp files
 releases.json
 versions.json
diff --git a/docs/docs/api/api.md b/docs/docs/api/api.md
index 0d8b24b128..7f2c9328d0 100644
--- a/docs/docs/api/api.md
+++ b/docs/docs/api/api.md
@@ -17,6 +17,17 @@ The API is self-documenting, and the documentation is provided alongside any Inv
 {% include 'img.html' %}
 {% endwith %}
 
+### Schema Description
+    The API schema is also documented in the [API Schema](./schema.md) page.
+
+### Generating Schema File
+
+If you want to generate the API schema file yourself (for example to use with an external client, use the `invoke schema` command. Run with the `-help` command to see available options.
+
+```
+invoke schema -help
+```
+
 ## Authentication
 
 Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access.
diff --git a/docs/docs/api/schema.md b/docs/docs/api/schema.md
new file mode 100644
index 0000000000..441e977e2e
--- /dev/null
+++ b/docs/docs/api/schema.md
@@ -0,0 +1,40 @@
+---
+title: InvenTree API Schema
+---
+
+The InvenTree API is implemented using the [Django REST framework](https://www.django-rest-framework.org).
+The API schema as documented below is generated using the [drf-spectactular](https://github.com/tfranzel/drf-spectacular/) extension.
+
+## API Version
+
+This documentation is for API version: `171`
+
+!!! tip "API Schema History"
+    We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/).
+
+## API Schema File
+
+The API schema file is available for download, and can be used for generating client libraries, or for testing API endpoints.
+
+## API Schema Documentation
+
+API schema documentation is split into the following categories:
+
+| Category | Description |
+| --- | --- |
+| [Authorization and Authentication](./schema/auth.md) | Authorization and Authentication |
+| [Background Task Management](./schema/background-task.md) | Background Task Management |
+| [Barcode Scanning](./schema/barcode.md) | Barcode Scanning |
+| [Bill of Materials](./schema/bom.md) | Bill of Materials |
+| [Build Order Management](./schema/build.md) | Build Order Management |
+| [Company Management](./schema/company.md) | Company Management |
+| [Label Printing](./schema/label.md) | Label Printing |
+| [External Machine Management](./schema/machine.md) | External Machine Management |
+| [External Order Management](./schema/order.md) | External Order Management |
+| [Parts and Part Categories](./schema/part.md) | Parts and Part Categories |
+| [Plugin Functionality](./schema/plugins.md) | Plugin Functionality |
+| [Report Generation](./schema/report.md) | Report Generation |
+| [Settings Management](./schema/settings.md) | Settings Management |
+| [Stock and Stock Locations](./schema/stock.md) | Stock and Stock Locations |
+| [User Management](./schema/user.md) | User Management |
+| [General](./schema/general.md) | General API endpoints |
diff --git a/docs/docs/api/schema/auth.md b/docs/docs/api/schema/auth.md
new file mode 100644
index 0000000000..62c8b50103
--- /dev/null
+++ b/docs/docs/api/schema/auth.md
@@ -0,0 +1,7 @@
+---
+title: Authorization and Authentication
+---
+
+The *Authorization and Authentication* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/auth.yml)]
diff --git a/docs/docs/api/schema/background-task.md b/docs/docs/api/schema/background-task.md
new file mode 100644
index 0000000000..b1d5ad0b92
--- /dev/null
+++ b/docs/docs/api/schema/background-task.md
@@ -0,0 +1,7 @@
+---
+title: Background Task Management
+---
+
+The *Background Task Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/background-task.yml)]
diff --git a/docs/docs/api/schema/barcode.md b/docs/docs/api/schema/barcode.md
new file mode 100644
index 0000000000..c0f5cab2bf
--- /dev/null
+++ b/docs/docs/api/schema/barcode.md
@@ -0,0 +1,7 @@
+---
+title: Barcode Scanning
+---
+
+The *Barcode Scanning* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/barcode.yml)]
diff --git a/docs/docs/api/schema/bom.md b/docs/docs/api/schema/bom.md
new file mode 100644
index 0000000000..cdfd1ff9c2
--- /dev/null
+++ b/docs/docs/api/schema/bom.md
@@ -0,0 +1,7 @@
+---
+title: Bill of Materials
+---
+
+The *Bill of Materials* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/bom.yml)]
diff --git a/docs/docs/api/schema/build.md b/docs/docs/api/schema/build.md
new file mode 100644
index 0000000000..3de0e521c6
--- /dev/null
+++ b/docs/docs/api/schema/build.md
@@ -0,0 +1,7 @@
+---
+title: Build Order Management
+---
+
+The *Build Order Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/build.yml)]
diff --git a/docs/docs/api/schema/company.md b/docs/docs/api/schema/company.md
new file mode 100644
index 0000000000..924d899ad4
--- /dev/null
+++ b/docs/docs/api/schema/company.md
@@ -0,0 +1,7 @@
+---
+title: Company Management
+---
+
+The *Company Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/company.yml)]
diff --git a/docs/docs/api/schema/general.md b/docs/docs/api/schema/general.md
new file mode 100644
index 0000000000..5da17b815d
--- /dev/null
+++ b/docs/docs/api/schema/general.md
@@ -0,0 +1,7 @@
+---
+title: General API Endpoints
+---
+
+The *General API Endpoints* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/general.yml)]
diff --git a/docs/docs/api/schema/label.md b/docs/docs/api/schema/label.md
new file mode 100644
index 0000000000..d4bc47e57c
--- /dev/null
+++ b/docs/docs/api/schema/label.md
@@ -0,0 +1,7 @@
+---
+title: Label Printing
+---
+
+The *Label Printing* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/label.yml)]
diff --git a/docs/docs/api/schema/machine.md b/docs/docs/api/schema/machine.md
new file mode 100644
index 0000000000..2fbadd41e6
--- /dev/null
+++ b/docs/docs/api/schema/machine.md
@@ -0,0 +1,7 @@
+---
+title: External Machine Management
+---
+
+The *External Machine Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/machine.yml)]
diff --git a/docs/docs/api/schema/order.md b/docs/docs/api/schema/order.md
new file mode 100644
index 0000000000..7f6c8fdfd7
--- /dev/null
+++ b/docs/docs/api/schema/order.md
@@ -0,0 +1,7 @@
+---
+title: External Order Management
+---
+
+The *External Order Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/order.yml)]
diff --git a/docs/docs/api/schema/part.md b/docs/docs/api/schema/part.md
new file mode 100644
index 0000000000..67c73eb0fb
--- /dev/null
+++ b/docs/docs/api/schema/part.md
@@ -0,0 +1,7 @@
+---
+title: Parts and Part Categories
+---
+
+The *Parts and Part Categories* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/part.yml)]
diff --git a/docs/docs/api/schema/plugins.md b/docs/docs/api/schema/plugins.md
new file mode 100644
index 0000000000..ee0263cffa
--- /dev/null
+++ b/docs/docs/api/schema/plugins.md
@@ -0,0 +1,7 @@
+---
+title: Plugin Functionality
+---
+
+The *Plugin Functionality* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/plugins.yml)]
diff --git a/docs/docs/api/schema/report.md b/docs/docs/api/schema/report.md
new file mode 100644
index 0000000000..dfad6d74be
--- /dev/null
+++ b/docs/docs/api/schema/report.md
@@ -0,0 +1,7 @@
+---
+title: Report Generation
+---
+
+The *Report Generation* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/report.yml)]
diff --git a/docs/docs/api/schema/settings.md b/docs/docs/api/schema/settings.md
new file mode 100644
index 0000000000..4a6d4f4337
--- /dev/null
+++ b/docs/docs/api/schema/settings.md
@@ -0,0 +1,7 @@
+---
+title: Settings Management
+---
+
+The *Settings Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/settings.yml)]
diff --git a/docs/docs/api/schema/stock.md b/docs/docs/api/schema/stock.md
new file mode 100644
index 0000000000..7b961e4b5b
--- /dev/null
+++ b/docs/docs/api/schema/stock.md
@@ -0,0 +1,7 @@
+---
+title: Stock and Stock Locations
+---
+
+The *Stock and Stock Locations* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/stock.yml)]
diff --git a/docs/docs/api/schema/user.md b/docs/docs/api/schema/user.md
new file mode 100644
index 0000000000..e0ebba2770
--- /dev/null
+++ b/docs/docs/api/schema/user.md
@@ -0,0 +1,7 @@
+---
+title: User Management
+---
+
+The *User Management* section of the InvenTree API schema is documented below.
+
+[OAD(./docs/docs/api/schema/user.yml)]
diff --git a/docs/docs/concepts/units.md b/docs/docs/concepts/units.md
index d65d122bc5..b15d4e40f1 100644
--- a/docs/docs/concepts/units.md
+++ b/docs/docs/concepts/units.md
@@ -48,7 +48,7 @@ The [unit of measure](../part/part.md#units-of-measure) field for the [Part](../
 
 ### Supplier Part
 
-The [supplier part](../part/part/#supplier-parts) model uses real-world units to convert between supplier part quantities and internal stock quantities. Unit conversion rules ensure that only compatible unit types can be supplied
+The [supplier part](../part/part.md/#supplier-parts) model uses real-world units to convert between supplier part quantities and internal stock quantities. Unit conversion rules ensure that only compatible unit types can be supplied
 
 ### Part Parameter
 
diff --git a/docs/docs/extend/plugins/tags.md b/docs/docs/extend/plugins/tags.md
index ebcfdc3502..c7853e0baa 100644
--- a/docs/docs/extend/plugins/tags.md
+++ b/docs/docs/extend/plugins/tags.md
@@ -8,7 +8,7 @@ Several models in InvenTree can be tagged with arbitrary tags. Tags are useful f
 Tags are shared between all models that can be tagged.
 
 The following models can be tagged:
-- [Parts](../../part/part.md) and [Supplier Parts](../../order/company#supplier-parts)/[Manufacturer Part](../../order/company#manufacturer-parts)
+- [Parts](../../part/part.md) and [Supplier Parts](../../order/company.md#supplier-parts)/[Manufacturer Part](../../order/company.md#manufacturer-parts)
 - [Stock Items](../../stock/stock.md#stock-item) / [Stock Location](../../stock/stock.md#stock-location)
 
 
diff --git a/docs/docs/part/create.md b/docs/docs/part/create.md
index 0eab451789..46750fbd67 100644
--- a/docs/docs/part/create.md
+++ b/docs/docs/part/create.md
@@ -64,6 +64,6 @@ If the *Add Supplier Data* option is checked, then supplier part and manufacture
 
 The following alternative methods for creating parts are supported:
 
-- [Via the REST API](../../api/api)
-- [Using the Python library](../../api/python)
-- [Within the Admin interface](../../settings/admin)
+- [Via the REST API](../api/api.md)
+- [Using the Python library](../api/python/python.md)
+- [Within the Admin interface](../settings/admin.md)
diff --git a/docs/docs/part/notification.md b/docs/docs/part/notification.md
index 48d0bffde9..27aed5a9cd 100644
--- a/docs/docs/part/notification.md
+++ b/docs/docs/part/notification.md
@@ -7,7 +7,7 @@ title: Part Notifications
 Users can select to receive notifications when certain events occur.
 
 !!! warning "Email Configuration Required"
-    External notifications require correct [email configuration](../../start/config/#email-settings). They also need to be enabled in the settings under notifications`.
+    External notifications require correct [email configuration](../start/config.md#email-settings). They also need to be enabled in the settings under notifications`.
 
 !!! warning "Valid Email Address"
     Each user must have a valid email address associated with their account to receive email notifications
@@ -50,7 +50,7 @@ Any users who are subscribed to notifications for the part in question will rece
 
 ### Build Order Notification
 
-When a new [Build Order](../../build/build/) is created, the InvenTree software checks to see if any of the parts required to complete the order are low on stock.
+When a new [Build Order](../build/build.md) is created, the InvenTree software checks to see if any of the parts required to complete the order are low on stock.
 
 If there are any parts with low stock, a notification is generated for any users subscribed to notifications for the part being built.
 
diff --git a/docs/docs/part/trackable.md b/docs/docs/part/trackable.md
index 55aba96f89..4810c0a94c 100644
--- a/docs/docs/part/trackable.md
+++ b/docs/docs/part/trackable.md
@@ -2,7 +2,7 @@
 title: Trackable Parts
 ---
 
-Denoting a part as *Trackble* changes the way that [stock items](../../stock/stock) associated with the particular part are handled in the database. A trackable part also has more restrictions imposed by the database scheme.
+Denoting a part as *Trackble* changes the way that [stock items](../stock/stock.md) associated with the particular part are handled in the database. A trackable part also has more restrictions imposed by the database scheme.
 
 ## Stock Tracking
 
diff --git a/docs/docs/releases/0.1.5.md b/docs/docs/releases/0.1.5.md
index 593c68cc39..1199a8e317 100644
--- a/docs/docs/releases/0.1.5.md
+++ b/docs/docs/releases/0.1.5.md
@@ -24,7 +24,7 @@ Refer to the [build documentation](../build/build.md#overdue-builds) for more in
 
 ### Stock Item Expiry
 
-[#1202](https://github.com/inventree/InvenTree/pull/1202) introduces the concept of an *Expiry Date* for Stock Items. For further information, refer to the [expiry documentation](../../stock/expiry).
+[#1202](https://github.com/inventree/InvenTree/pull/1202) introduces the concept of an *Expiry Date* for Stock Items. For further information, refer to the [expiry documentation](../stock/expiry.md).
 
 ### Stock Ownership
 
diff --git a/docs/docs/releases/0.2.1.md b/docs/docs/releases/0.2.1.md
index 036e03ec7b..c992bd7db6 100644
--- a/docs/docs/releases/0.2.1.md
+++ b/docs/docs/releases/0.2.1.md
@@ -14,7 +14,7 @@ title: Release 0.2.1
 
 !!! warning "Configuration Required"
     Refer to the [email configuration
-    options](../../start/config/#email-settings).
+    options](../start/config.md#email-settings).
 
 ### Manufacturer Parts
 
diff --git a/docs/docs/releases/0.6.0.md b/docs/docs/releases/0.6.0.md
index 90a0971499..5edd0d2d97 100644
--- a/docs/docs/releases/0.6.0.md
+++ b/docs/docs/releases/0.6.0.md
@@ -54,7 +54,7 @@ PR [#2119](https://github.com/inventree/InvenTree/pull/2119) adds the ability to
 
 ### SSO Support
 
-PR [#2017](https://github.com/inventree/InvenTree/pull/2017) adds support for SSO (single sign on) authentication. SSO integration requires configuration by the system administrator. Refer to the [SSO documentation](../settings/sso) for further information.
+PR [#2017](https://github.com/inventree/InvenTree/pull/2017) adds support for SSO (single sign on) authentication. SSO integration requires configuration by the system administrator. Refer to the [SSO documentation](../settings/SSO.md) for further information.
 
 ### BOM Substitution
 
@@ -74,7 +74,7 @@ PR [#2208](https://github.com/inventree/InvenTree/pull/2208) provides notificati
 
 ### MFA Support
 
-PR [#2221](https://github.com/inventree/InvenTree/pull/2221) adds support for MFA (multi factor authentication). This enables admins to require all users to enable MFA as a second auth step. Refer to the [documentation](../settings/mfa) for further information.
+PR [#2221](https://github.com/inventree/InvenTree/pull/2221) adds support for MFA (multi factor authentication). This enables admins to require all users to enable MFA as a second auth step. Refer to the [documentation](../settings/MFA.md) for further information.
 ### Stock Item Forms
 
 PR [#2198](https://github.com/inventree/InvenTree/pull/2198) provides a major refactor of stock item forms, for creating and editing stock items. These forms have been migrated to the REST API, providing a much more responsive user experience.
diff --git a/docs/docs/stock/owner.md b/docs/docs/stock/owner.md
index 9fe96abb31..e782fe4fda 100644
--- a/docs/docs/stock/owner.md
+++ b/docs/docs/stock/owner.md
@@ -33,7 +33,7 @@ When selecting an owner, in the drop-down list, groups are annotated with the <s
 To specify the owner of a stock location, navigate to the stock location detail page. Click on the <span class='fas fa-sitemap'></span> icon under the location's name then click on "Edit Location".
 
 !!! warning
-	If you cannot see the <span class='fas fa-sitemap'></span> icon, it means that you do **not** have permissions to edit stock locations. Refer to [the permissions documentation](../../settings/permissions/#roles) and/or contact your InvenTree administrator.
+	If you cannot see the <span class='fas fa-sitemap'></span> icon, it means that you do **not** have permissions to edit stock locations. Refer to [the permissions documentation](../settings/permissions.md#roles) and/or contact your InvenTree administrator.
 
 In the "Edit Stock Location" form, select the owner and click the "Submit" button:
 
@@ -54,7 +54,7 @@ Setting the owner of stock location will automatically:
 To specify the owner of a stock item, navigate to the stock item detail page. Click on the <span class='fas fa-tools'></span> icon under the item's name then click on "Edit stock item".
 
 !!! warning
-	If you cannot see the <span class='fas fa-tools'></span> icon, it means that you do **not** have permissions to edit stock items. Refer to [the permissions documentation](../../settings/permissions/#roles) and/or contact your InvenTree administrator.
+	If you cannot see the <span class='fas fa-tools'></span> icon, it means that you do **not** have permissions to edit stock items. Refer to [the permissions documentation](../settings/permissions.md/#roles) and/or contact your InvenTree administrator.
 
 In the "Edit Stock Item" form, select the owner and click the "Save" button:
 
diff --git a/docs/docs/stylesheets/neoteroi-mkdocs.css b/docs/docs/stylesheets/neoteroi-mkdocs.css
new file mode 100644
index 0000000000..ee7d53a554
--- /dev/null
+++ b/docs/docs/stylesheets/neoteroi-mkdocs.css
@@ -0,0 +1,1399 @@
+/**
+ *  All CSS for the neoteroi.projects.gantt extension.
+ *
+ *  https://github.com/Neoteroi/mkdocs-plugins
+**/
+:root {
+  --nt-color-0: #CD853F;
+  --nt-color-1: #B22222;
+  --nt-color-2: #000080;
+  --nt-color-3: #4B0082;
+  --nt-color-4: #3CB371;
+  --nt-color-5: #D2B48C;
+  --nt-color-6: #FF00FF;
+  --nt-color-7: #98FB98;
+  --nt-color-8: #FFEBCD;
+  --nt-color-9: #2E8B57;
+  --nt-color-10: #6A5ACD;
+  --nt-color-11: #48D1CC;
+  --nt-color-12: #FFA500;
+  --nt-color-13: #F4A460;
+  --nt-color-14: #A52A2A;
+  --nt-color-15: #FFE4C4;
+  --nt-color-16: #FF4500;
+  --nt-color-17: #AFEEEE;
+  --nt-color-18: #FA8072;
+  --nt-color-19: #2F4F4F;
+  --nt-color-20: #FFDAB9;
+  --nt-color-21: #BC8F8F;
+  --nt-color-22: #FFC0CB;
+  --nt-color-23: #00FA9A;
+  --nt-color-24: #F0FFF0;
+  --nt-color-25: #FFFACD;
+  --nt-color-26: #F5F5F5;
+  --nt-color-27: #FF6347;
+  --nt-color-28: #FFFFF0;
+  --nt-color-29: #7FFFD4;
+  --nt-color-30: #E9967A;
+  --nt-color-31: #7B68EE;
+  --nt-color-32: #FFF8DC;
+  --nt-color-33: #0000CD;
+  --nt-color-34: #D2691E;
+  --nt-color-35: #708090;
+  --nt-color-36: #5F9EA0;
+  --nt-color-37: #008080;
+  --nt-color-38: #008000;
+  --nt-color-39: #FFE4E1;
+  --nt-color-40: #FFFF00;
+  --nt-color-41: #FFFAF0;
+  --nt-color-42: #DCDCDC;
+  --nt-color-43: #ADFF2F;
+  --nt-color-44: #ADD8E6;
+  --nt-color-45: #8B008B;
+  --nt-color-46: #7FFF00;
+  --nt-color-47: #800000;
+  --nt-color-48: #20B2AA;
+  --nt-color-49: #556B2F;
+  --nt-color-50: #778899;
+  --nt-color-51: #E6E6FA;
+  --nt-color-52: #FFFAFA;
+  --nt-color-53: #FF7F50;
+  --nt-color-54: #FF0000;
+  --nt-color-55: #F5DEB3;
+  --nt-color-56: #008B8B;
+  --nt-color-57: #66CDAA;
+  --nt-color-58: #808000;
+  --nt-color-59: #FAF0E6;
+  --nt-color-60: #00BFFF;
+  --nt-color-61: #C71585;
+  --nt-color-62: #00FFFF;
+  --nt-color-63: #8B4513;
+  --nt-color-64: #F0F8FF;
+  --nt-color-65: #FAEBD7;
+  --nt-color-66: #8B0000;
+  --nt-color-67: #4682B4;
+  --nt-color-68: #F0E68C;
+  --nt-color-69: #BDB76B;
+  --nt-color-70: #A0522D;
+  --nt-color-71: #FAFAD2;
+  --nt-color-72: #FFD700;
+  --nt-color-73: #DEB887;
+  --nt-color-74: #E0FFFF;
+  --nt-color-75: #8A2BE2;
+  --nt-color-76: #32CD32;
+  --nt-color-77: #87CEFA;
+  --nt-color-78: #00CED1;
+  --nt-color-79: #696969;
+  --nt-color-80: #DDA0DD;
+  --nt-color-81: #EE82EE;
+  --nt-color-82: #FFB6C1;
+  --nt-color-83: #8FBC8F;
+  --nt-color-84: #D8BFD8;
+  --nt-color-85: #9400D3;
+  --nt-color-86: #A9A9A9;
+  --nt-color-87: #FFFFE0;
+  --nt-color-88: #FFF5EE;
+  --nt-color-89: #FFF0F5;
+  --nt-color-90: #FFDEAD;
+  --nt-color-91: #800080;
+  --nt-color-92: #B0E0E6;
+  --nt-color-93: #9932CC;
+  --nt-color-94: #DAA520;
+  --nt-color-95: #F0FFFF;
+  --nt-color-96: #40E0D0;
+  --nt-color-97: #00FF7F;
+  --nt-color-98: #006400;
+  --nt-color-99: #808080;
+  --nt-color-100: #87CEEB;
+  --nt-color-101: #0000FF;
+  --nt-color-102: #6495ED;
+  --nt-color-103: #FDF5E6;
+  --nt-color-104: #B8860B;
+  --nt-color-105: #BA55D3;
+  --nt-color-106: #C0C0C0;
+  --nt-color-107: #000000;
+  --nt-color-108: #F08080;
+  --nt-color-109: #B0C4DE;
+  --nt-color-110: #00008B;
+  --nt-color-111: #6B8E23;
+  --nt-color-112: #FFE4B5;
+  --nt-color-113: #FFA07A;
+  --nt-color-114: #9ACD32;
+  --nt-color-115: #FFFFFF;
+  --nt-color-116: #F5F5DC;
+  --nt-color-117: #90EE90;
+  --nt-color-118: #1E90FF;
+  --nt-color-119: #7CFC00;
+  --nt-color-120: #FF69B4;
+  --nt-color-121: #F8F8FF;
+  --nt-color-122: #F5FFFA;
+  --nt-color-123: #00FF00;
+  --nt-color-124: #D3D3D3;
+  --nt-color-125: #DB7093;
+  --nt-color-126: #DA70D6;
+  --nt-color-127: #FF1493;
+  --nt-color-128: #228B22;
+  --nt-color-129: #FFEFD5;
+  --nt-color-130: #4169E1;
+  --nt-color-131: #191970;
+  --nt-color-132: #9370DB;
+  --nt-color-133: #483D8B;
+  --nt-color-134: #FF8C00;
+  --nt-color-135: #EEE8AA;
+  --nt-color-136: #CD5C5C;
+  --nt-color-137: #DC143C;
+}
+
+:root {
+  --nt-group-0-main: #000000;
+  --nt-group-0-dark: #FFFFFF;
+  --nt-group-0-light: #000000;
+  --nt-group-0-main-bg: #F44336;
+  --nt-group-0-dark-bg: #BA000D;
+  --nt-group-0-light-bg: #FF7961;
+  --nt-group-1-main: #000000;
+  --nt-group-1-dark: #FFFFFF;
+  --nt-group-1-light: #000000;
+  --nt-group-1-main-bg: #E91E63;
+  --nt-group-1-dark-bg: #B0003A;
+  --nt-group-1-light-bg: #FF6090;
+  --nt-group-2-main: #FFFFFF;
+  --nt-group-2-dark: #FFFFFF;
+  --nt-group-2-light: #000000;
+  --nt-group-2-main-bg: #9C27B0;
+  --nt-group-2-dark-bg: #6A0080;
+  --nt-group-2-light-bg: #D05CE3;
+  --nt-group-3-main: #FFFFFF;
+  --nt-group-3-dark: #FFFFFF;
+  --nt-group-3-light: #000000;
+  --nt-group-3-main-bg: #673AB7;
+  --nt-group-3-dark-bg: #320B86;
+  --nt-group-3-light-bg: #9A67EA;
+  --nt-group-4-main: #FFFFFF;
+  --nt-group-4-dark: #FFFFFF;
+  --nt-group-4-light: #000000;
+  --nt-group-4-main-bg: #3F51B5;
+  --nt-group-4-dark-bg: #002984;
+  --nt-group-4-light-bg: #757DE8;
+  --nt-group-5-main: #000000;
+  --nt-group-5-dark: #FFFFFF;
+  --nt-group-5-light: #000000;
+  --nt-group-5-main-bg: #2196F3;
+  --nt-group-5-dark-bg: #0069C0;
+  --nt-group-5-light-bg: #6EC6FF;
+  --nt-group-6-main: #000000;
+  --nt-group-6-dark: #FFFFFF;
+  --nt-group-6-light: #000000;
+  --nt-group-6-main-bg: #03A9F4;
+  --nt-group-6-dark-bg: #007AC1;
+  --nt-group-6-light-bg: #67DAFF;
+  --nt-group-7-main: #000000;
+  --nt-group-7-dark: #000000;
+  --nt-group-7-light: #000000;
+  --nt-group-7-main-bg: #00BCD4;
+  --nt-group-7-dark-bg: #008BA3;
+  --nt-group-7-light-bg: #62EFFF;
+  --nt-group-8-main: #000000;
+  --nt-group-8-dark: #FFFFFF;
+  --nt-group-8-light: #000000;
+  --nt-group-8-main-bg: #009688;
+  --nt-group-8-dark-bg: #00675B;
+  --nt-group-8-light-bg: #52C7B8;
+  --nt-group-9-main: #000000;
+  --nt-group-9-dark: #FFFFFF;
+  --nt-group-9-light: #000000;
+  --nt-group-9-main-bg: #4CAF50;
+  --nt-group-9-dark-bg: #087F23;
+  --nt-group-9-light-bg: #80E27E;
+  --nt-group-10-main: #000000;
+  --nt-group-10-dark: #000000;
+  --nt-group-10-light: #000000;
+  --nt-group-10-main-bg: #8BC34A;
+  --nt-group-10-dark-bg: #5A9216;
+  --nt-group-10-light-bg: #BEF67A;
+  --nt-group-11-main: #000000;
+  --nt-group-11-dark: #000000;
+  --nt-group-11-light: #000000;
+  --nt-group-11-main-bg: #CDDC39;
+  --nt-group-11-dark-bg: #99AA00;
+  --nt-group-11-light-bg: #FFFF6E;
+  --nt-group-12-main: #000000;
+  --nt-group-12-dark: #000000;
+  --nt-group-12-light: #000000;
+  --nt-group-12-main-bg: #FFEB3B;
+  --nt-group-12-dark-bg: #C8B900;
+  --nt-group-12-light-bg: #FFFF72;
+  --nt-group-13-main: #000000;
+  --nt-group-13-dark: #000000;
+  --nt-group-13-light: #000000;
+  --nt-group-13-main-bg: #FFC107;
+  --nt-group-13-dark-bg: #C79100;
+  --nt-group-13-light-bg: #FFF350;
+  --nt-group-14-main: #000000;
+  --nt-group-14-dark: #000000;
+  --nt-group-14-light: #000000;
+  --nt-group-14-main-bg: #FF9800;
+  --nt-group-14-dark-bg: #C66900;
+  --nt-group-14-light-bg: #FFC947;
+  --nt-group-15-main: #000000;
+  --nt-group-15-dark: #FFFFFF;
+  --nt-group-15-light: #000000;
+  --nt-group-15-main-bg: #FF5722;
+  --nt-group-15-dark-bg: #C41C00;
+  --nt-group-15-light-bg: #FF8A50;
+  --nt-group-16-main: #FFFFFF;
+  --nt-group-16-dark: #FFFFFF;
+  --nt-group-16-light: #000000;
+  --nt-group-16-main-bg: #795548;
+  --nt-group-16-dark-bg: #4B2C20;
+  --nt-group-16-light-bg: #A98274;
+  --nt-group-17-main: #000000;
+  --nt-group-17-dark: #FFFFFF;
+  --nt-group-17-light: #000000;
+  --nt-group-17-main-bg: #9E9E9E;
+  --nt-group-17-dark-bg: #707070;
+  --nt-group-17-light-bg: #CFCFCF;
+  --nt-group-18-main: #000000;
+  --nt-group-18-dark: #FFFFFF;
+  --nt-group-18-light: #000000;
+  --nt-group-18-main-bg: #607D8B;
+  --nt-group-18-dark-bg: #34515E;
+  --nt-group-18-light-bg: #8EACBB;
+}
+
+.nt-pastello {
+  --nt-group-0-main: #000000;
+  --nt-group-0-dark: #000000;
+  --nt-group-0-light: #000000;
+  --nt-group-0-main-bg: #EF9A9A;
+  --nt-group-0-dark-bg: #BA6B6C;
+  --nt-group-0-light-bg: #FFCCCB;
+  --nt-group-1-main: #000000;
+  --nt-group-1-dark: #000000;
+  --nt-group-1-light: #000000;
+  --nt-group-1-main-bg: #F48FB1;
+  --nt-group-1-dark-bg: #BF5F82;
+  --nt-group-1-light-bg: #FFC1E3;
+  --nt-group-2-main: #000000;
+  --nt-group-2-dark: #000000;
+  --nt-group-2-light: #000000;
+  --nt-group-2-main-bg: #CE93D8;
+  --nt-group-2-dark-bg: #9C64A6;
+  --nt-group-2-light-bg: #FFC4FF;
+  --nt-group-3-main: #000000;
+  --nt-group-3-dark: #000000;
+  --nt-group-3-light: #000000;
+  --nt-group-3-main-bg: #B39DDB;
+  --nt-group-3-dark-bg: #836FA9;
+  --nt-group-3-light-bg: #E6CEFF;
+  --nt-group-4-main: #000000;
+  --nt-group-4-dark: #000000;
+  --nt-group-4-light: #000000;
+  --nt-group-4-main-bg: #9FA8DA;
+  --nt-group-4-dark-bg: #6F79A8;
+  --nt-group-4-light-bg: #D1D9FF;
+  --nt-group-5-main: #000000;
+  --nt-group-5-dark: #000000;
+  --nt-group-5-light: #000000;
+  --nt-group-5-main-bg: #90CAF9;
+  --nt-group-5-dark-bg: #5D99C6;
+  --nt-group-5-light-bg: #C3FDFF;
+  --nt-group-6-main: #000000;
+  --nt-group-6-dark: #000000;
+  --nt-group-6-light: #000000;
+  --nt-group-6-main-bg: #81D4FA;
+  --nt-group-6-dark-bg: #4BA3C7;
+  --nt-group-6-light-bg: #B6FFFF;
+  --nt-group-7-main: #000000;
+  --nt-group-7-dark: #000000;
+  --nt-group-7-light: #000000;
+  --nt-group-7-main-bg: #80DEEA;
+  --nt-group-7-dark-bg: #4BACB8;
+  --nt-group-7-light-bg: #B4FFFF;
+  --nt-group-8-main: #000000;
+  --nt-group-8-dark: #000000;
+  --nt-group-8-light: #000000;
+  --nt-group-8-main-bg: #80CBC4;
+  --nt-group-8-dark-bg: #4F9A94;
+  --nt-group-8-light-bg: #B2FEF7;
+  --nt-group-9-main: #000000;
+  --nt-group-9-dark: #000000;
+  --nt-group-9-light: #000000;
+  --nt-group-9-main-bg: #A5D6A7;
+  --nt-group-9-dark-bg: #75A478;
+  --nt-group-9-light-bg: #D7FFD9;
+  --nt-group-10-main: #000000;
+  --nt-group-10-dark: #000000;
+  --nt-group-10-light: #000000;
+  --nt-group-10-main-bg: #C5E1A5;
+  --nt-group-10-dark-bg: #94AF76;
+  --nt-group-10-light-bg: #F8FFD7;
+  --nt-group-11-main: #000000;
+  --nt-group-11-dark: #000000;
+  --nt-group-11-light: #000000;
+  --nt-group-11-main-bg: #E6EE9C;
+  --nt-group-11-dark-bg: #B3BC6D;
+  --nt-group-11-light-bg: #FFFFCE;
+  --nt-group-12-main: #000000;
+  --nt-group-12-dark: #000000;
+  --nt-group-12-light: #000000;
+  --nt-group-12-main-bg: #FFF59D;
+  --nt-group-12-dark-bg: #CBC26D;
+  --nt-group-12-light-bg: #FFFFCF;
+  --nt-group-13-main: #000000;
+  --nt-group-13-dark: #000000;
+  --nt-group-13-light: #000000;
+  --nt-group-13-main-bg: #FFE082;
+  --nt-group-13-dark-bg: #CAAE53;
+  --nt-group-13-light-bg: #FFFFB3;
+  --nt-group-14-main: #000000;
+  --nt-group-14-dark: #000000;
+  --nt-group-14-light: #000000;
+  --nt-group-14-main-bg: #FFCC80;
+  --nt-group-14-dark-bg: #CA9B52;
+  --nt-group-14-light-bg: #FFFFB0;
+  --nt-group-15-main: #000000;
+  --nt-group-15-dark: #000000;
+  --nt-group-15-light: #000000;
+  --nt-group-15-main-bg: #FFAB91;
+  --nt-group-15-dark-bg: #C97B63;
+  --nt-group-15-light-bg: #FFDDC1;
+  --nt-group-16-main: #000000;
+  --nt-group-16-dark: #000000;
+  --nt-group-16-light: #000000;
+  --nt-group-16-main-bg: #BCAAA4;
+  --nt-group-16-dark-bg: #8C7B75;
+  --nt-group-16-light-bg: #EFDCD5;
+  --nt-group-17-main: #000000;
+  --nt-group-17-dark: #000000;
+  --nt-group-17-light: #000000;
+  --nt-group-17-main-bg: #EEEEEE;
+  --nt-group-17-dark-bg: #BCBCBC;
+  --nt-group-17-light-bg: #FFFFFF;
+  --nt-group-18-main: #000000;
+  --nt-group-18-dark: #000000;
+  --nt-group-18-light: #000000;
+  --nt-group-18-main-bg: #B0BEC5;
+  --nt-group-18-dark-bg: #808E95;
+  --nt-group-18-light-bg: #E2F1F8;
+}
+
+.nt-group-0 .nt-plan-group-summary,
+.nt-group-0 .nt-timeline-dot {
+  color: var(--nt-group-0-dark);
+  background-color: var(--nt-group-0-dark-bg);
+}
+.nt-group-0 .period {
+  color: var(--nt-group-0-main);
+  background-color: var(--nt-group-0-main-bg);
+}
+
+.nt-group-1 .nt-plan-group-summary,
+.nt-group-1 .nt-timeline-dot {
+  color: var(--nt-group-1-dark);
+  background-color: var(--nt-group-1-dark-bg);
+}
+.nt-group-1 .period {
+  color: var(--nt-group-1-main);
+  background-color: var(--nt-group-1-main-bg);
+}
+
+.nt-group-2 .nt-plan-group-summary,
+.nt-group-2 .nt-timeline-dot {
+  color: var(--nt-group-2-dark);
+  background-color: var(--nt-group-2-dark-bg);
+}
+.nt-group-2 .period {
+  color: var(--nt-group-2-main);
+  background-color: var(--nt-group-2-main-bg);
+}
+
+.nt-group-3 .nt-plan-group-summary,
+.nt-group-3 .nt-timeline-dot {
+  color: var(--nt-group-3-dark);
+  background-color: var(--nt-group-3-dark-bg);
+}
+.nt-group-3 .period {
+  color: var(--nt-group-3-main);
+  background-color: var(--nt-group-3-main-bg);
+}
+
+.nt-group-4 .nt-plan-group-summary,
+.nt-group-4 .nt-timeline-dot {
+  color: var(--nt-group-4-dark);
+  background-color: var(--nt-group-4-dark-bg);
+}
+.nt-group-4 .period {
+  color: var(--nt-group-4-main);
+  background-color: var(--nt-group-4-main-bg);
+}
+
+.nt-group-5 .nt-plan-group-summary,
+.nt-group-5 .nt-timeline-dot {
+  color: var(--nt-group-5-dark);
+  background-color: var(--nt-group-5-dark-bg);
+}
+.nt-group-5 .period {
+  color: var(--nt-group-5-main);
+  background-color: var(--nt-group-5-main-bg);
+}
+
+.nt-group-6 .nt-plan-group-summary,
+.nt-group-6 .nt-timeline-dot {
+  color: var(--nt-group-6-dark);
+  background-color: var(--nt-group-6-dark-bg);
+}
+.nt-group-6 .period {
+  color: var(--nt-group-6-main);
+  background-color: var(--nt-group-6-main-bg);
+}
+
+.nt-group-7 .nt-plan-group-summary,
+.nt-group-7 .nt-timeline-dot {
+  color: var(--nt-group-7-dark);
+  background-color: var(--nt-group-7-dark-bg);
+}
+.nt-group-7 .period {
+  color: var(--nt-group-7-main);
+  background-color: var(--nt-group-7-main-bg);
+}
+
+.nt-group-8 .nt-plan-group-summary,
+.nt-group-8 .nt-timeline-dot {
+  color: var(--nt-group-8-dark);
+  background-color: var(--nt-group-8-dark-bg);
+}
+.nt-group-8 .period {
+  color: var(--nt-group-8-main);
+  background-color: var(--nt-group-8-main-bg);
+}
+
+.nt-group-9 .nt-plan-group-summary,
+.nt-group-9 .nt-timeline-dot {
+  color: var(--nt-group-9-dark);
+  background-color: var(--nt-group-9-dark-bg);
+}
+.nt-group-9 .period {
+  color: var(--nt-group-9-main);
+  background-color: var(--nt-group-9-main-bg);
+}
+
+.nt-group-10 .nt-plan-group-summary,
+.nt-group-10 .nt-timeline-dot {
+  color: var(--nt-group-10-dark);
+  background-color: var(--nt-group-10-dark-bg);
+}
+.nt-group-10 .period {
+  color: var(--nt-group-10-main);
+  background-color: var(--nt-group-10-main-bg);
+}
+
+.nt-group-11 .nt-plan-group-summary,
+.nt-group-11 .nt-timeline-dot {
+  color: var(--nt-group-11-dark);
+  background-color: var(--nt-group-11-dark-bg);
+}
+.nt-group-11 .period {
+  color: var(--nt-group-11-main);
+  background-color: var(--nt-group-11-main-bg);
+}
+
+.nt-group-12 .nt-plan-group-summary,
+.nt-group-12 .nt-timeline-dot {
+  color: var(--nt-group-12-dark);
+  background-color: var(--nt-group-12-dark-bg);
+}
+.nt-group-12 .period {
+  color: var(--nt-group-12-main);
+  background-color: var(--nt-group-12-main-bg);
+}
+
+.nt-group-13 .nt-plan-group-summary,
+.nt-group-13 .nt-timeline-dot {
+  color: var(--nt-group-13-dark);
+  background-color: var(--nt-group-13-dark-bg);
+}
+.nt-group-13 .period {
+  color: var(--nt-group-13-main);
+  background-color: var(--nt-group-13-main-bg);
+}
+
+.nt-group-14 .nt-plan-group-summary,
+.nt-group-14 .nt-timeline-dot {
+  color: var(--nt-group-14-dark);
+  background-color: var(--nt-group-14-dark-bg);
+}
+.nt-group-14 .period {
+  color: var(--nt-group-14-main);
+  background-color: var(--nt-group-14-main-bg);
+}
+
+.nt-group-15 .nt-plan-group-summary,
+.nt-group-15 .nt-timeline-dot {
+  color: var(--nt-group-15-dark);
+  background-color: var(--nt-group-15-dark-bg);
+}
+.nt-group-15 .period {
+  color: var(--nt-group-15-main);
+  background-color: var(--nt-group-15-main-bg);
+}
+
+.nt-group-16 .nt-plan-group-summary,
+.nt-group-16 .nt-timeline-dot {
+  color: var(--nt-group-16-dark);
+  background-color: var(--nt-group-16-dark-bg);
+}
+.nt-group-16 .period {
+  color: var(--nt-group-16-main);
+  background-color: var(--nt-group-16-main-bg);
+}
+
+.nt-group-17 .nt-plan-group-summary,
+.nt-group-17 .nt-timeline-dot {
+  color: var(--nt-group-17-dark);
+  background-color: var(--nt-group-17-dark-bg);
+}
+.nt-group-17 .period {
+  color: var(--nt-group-17-main);
+  background-color: var(--nt-group-17-main-bg);
+}
+
+.nt-group-18 .nt-plan-group-summary,
+.nt-group-18 .nt-timeline-dot {
+  color: var(--nt-group-18-dark);
+  background-color: var(--nt-group-18-dark-bg);
+}
+.nt-group-18 .period {
+  color: var(--nt-group-18-main);
+  background-color: var(--nt-group-18-main-bg);
+}
+
+/**
+ *  Extra CSS file for MkDocs and the neoteroi.timeline extension.
+ *
+ *  https://github.com/Neoteroi/mkdocs-plugins
+**/
+.nt-error {
+  border: 2px dashed darkred;
+  padding: 0 1rem;
+  background: #faf9ba;
+  color: darkred;
+}
+
+.nt-timeline {
+  margin-top: 30px;
+}
+.nt-timeline .nt-timeline-title {
+  font-size: 1.1rem;
+  margin-top: 0;
+}
+.nt-timeline .nt-timeline-sub-title {
+  margin-top: 0;
+}
+.nt-timeline .nt-timeline-content {
+  font-size: 0.8rem;
+  border-bottom: 2px dashed #ccc;
+  padding-bottom: 1.2rem;
+}
+.nt-timeline.horizontal .nt-timeline-items {
+  flex-direction: row;
+  overflow-x: scroll;
+}
+.nt-timeline.horizontal .nt-timeline-items > div {
+  min-width: 400px;
+  margin-right: 50px;
+}
+.nt-timeline.horizontal.reverse .nt-timeline-items {
+  flex-direction: row-reverse;
+}
+.nt-timeline.horizontal.center .nt-timeline-before {
+  background-image: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%);
+  background-repeat: no-repeat;
+  background-size: 100% 2px;
+  background-position: 0 center;
+}
+.nt-timeline.horizontal.center .nt-timeline-after {
+  background-image: linear-gradient(180deg, rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%);
+  background-repeat: no-repeat;
+  background-size: 100% 2px;
+  background-position: 0 center;
+}
+.nt-timeline.horizontal.center .nt-timeline-items {
+  background-image: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%);
+  background-repeat: no-repeat;
+  background-size: 100% 2px;
+  background-position: 0 center;
+}
+.nt-timeline.horizontal .nt-timeline-dot {
+  left: 50%;
+}
+.nt-timeline.horizontal .nt-timeline-dot:not(.bigger) {
+  top: calc(50% - 4px);
+}
+.nt-timeline.horizontal .nt-timeline-dot.bigger {
+  top: calc(50% - 15px);
+}
+.nt-timeline.vertical .nt-timeline-items {
+  flex-direction: column;
+}
+.nt-timeline.vertical.reverse .nt-timeline-items {
+  flex-direction: column-reverse;
+}
+.nt-timeline.vertical.center .nt-timeline-before {
+  background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%;
+}
+.nt-timeline.vertical.center .nt-timeline-after {
+  background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat center/2px 100%;
+}
+.nt-timeline.vertical.center .nt-timeline-items {
+  background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%;
+}
+.nt-timeline.vertical.center .nt-timeline-dot {
+  left: calc(50% - 10px);
+}
+.nt-timeline.vertical.center .nt-timeline-dot:not(.bigger) {
+  top: 10px;
+}
+.nt-timeline.vertical.center .nt-timeline-dot.bigger {
+  left: calc(50% - 20px);
+}
+.nt-timeline.vertical.left {
+  padding-left: 100px;
+}
+.nt-timeline.vertical.left .nt-timeline-item {
+  padding-left: 70px;
+}
+.nt-timeline.vertical.left .nt-timeline-sub-title {
+  left: -100px;
+  width: 100px;
+}
+.nt-timeline.vertical.left .nt-timeline-before {
+  background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%;
+}
+.nt-timeline.vertical.left .nt-timeline-after {
+  background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat 30px/2px 100%;
+}
+.nt-timeline.vertical.left .nt-timeline-items {
+  background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%;
+}
+.nt-timeline.vertical.left .nt-timeline-dot {
+  left: 21px;
+  top: 8px;
+}
+.nt-timeline.vertical.left .nt-timeline-dot.bigger {
+  top: 0px;
+  left: 10px;
+}
+.nt-timeline.vertical.right {
+  padding-right: 100px;
+}
+.nt-timeline.vertical.right .nt-timeline-sub-title {
+  right: -100px;
+  text-align: left;
+  width: 100px;
+}
+.nt-timeline.vertical.right .nt-timeline-item {
+  padding-right: 70px;
+}
+.nt-timeline.vertical.right .nt-timeline-before {
+  background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%;
+}
+.nt-timeline.vertical.right .nt-timeline-after {
+  background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat calc(100% - 30px)/2px 100%;
+}
+.nt-timeline.vertical.right .nt-timeline-items {
+  background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%;
+}
+.nt-timeline.vertical.right .nt-timeline-dot {
+  right: 21px;
+  top: 8px;
+}
+.nt-timeline.vertical.right .nt-timeline-dot.bigger {
+  top: 10px;
+  right: 10px;
+}
+
+.nt-timeline-items {
+  display: flex;
+  position: relative;
+}
+.nt-timeline-items > div {
+  min-height: 100px;
+  padding-top: 2px;
+  padding-bottom: 20px;
+}
+
+.nt-timeline-before {
+  content: "";
+  height: 15px;
+}
+
+.nt-timeline-after {
+  content: "";
+  height: 60px;
+  margin-bottom: 20px;
+}
+
+.nt-timeline-sub-title {
+  position: absolute;
+  width: 50%;
+  top: 4px;
+  font-size: 18px;
+  color: var(--nt-color-50);
+}
+
+[data-md-color-scheme=slate] .nt-timeline-sub-title {
+  color: var(--nt-color-51);
+}
+
+.nt-timeline-item {
+  position: relative;
+}
+
+.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item {
+  padding-left: calc(50% + 40px);
+}
+.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title {
+  left: 0;
+  padding-right: 40px;
+  text-align: right;
+}
+.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) {
+  padding-left: calc(50% + 40px);
+}
+.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title {
+  left: 0;
+  padding-right: 40px;
+  text-align: right;
+}
+.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) {
+  text-align: right;
+  padding-right: calc(50% + 40px);
+}
+.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title {
+  right: 0;
+  padding-left: 40px;
+  text-align: left;
+}
+
+.nt-timeline-dot {
+  position: relative;
+  width: 20px;
+  height: 20px;
+  border-radius: 100%;
+  background-color: #fc5b5b;
+  position: absolute;
+  top: 0px;
+  z-index: 2;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
+  border: 3px solid white;
+}
+.nt-timeline-dot:not(.bigger) .icon {
+  font-size: 10px;
+}
+.nt-timeline-dot.bigger {
+  width: 40px;
+  height: 40px;
+  padding: 3px;
+}
+.nt-timeline-dot .icon {
+  color: white;
+}
+
+/* Fix for webkit (Chrome, Safari) */
+@supports not (-moz-appearance: none) {
+  /*
+  This fix is necessary, for some reason, to render the timeline properly
+  inside `details` elements used by pymdownx. Firefox doesn't need this fix,
+  it renders elements properly.
+  */
+  details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title,
+details .nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title {
+    left: -40px;
+  }
+  details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title {
+    right: -40px;
+  }
+  details .nt-timeline.vertical.center .nt-timeline-dot {
+    left: calc(50% - 12px);
+  }
+  details .nt-timeline-dot.bigger {
+    font-size: 1rem !important;
+  }
+}
+/* default colors */
+.nt-timeline-item:nth-child(0) .nt-timeline-dot {
+  background-color: var(--nt-color-0);
+}
+
+.nt-timeline-item:nth-child(1) .nt-timeline-dot {
+  background-color: var(--nt-color-1);
+}
+
+.nt-timeline-item:nth-child(2) .nt-timeline-dot {
+  background-color: var(--nt-color-2);
+}
+
+.nt-timeline-item:nth-child(3) .nt-timeline-dot {
+  background-color: var(--nt-color-3);
+}
+
+.nt-timeline-item:nth-child(4) .nt-timeline-dot {
+  background-color: var(--nt-color-4);
+}
+
+.nt-timeline-item:nth-child(5) .nt-timeline-dot {
+  background-color: var(--nt-color-5);
+}
+
+.nt-timeline-item:nth-child(6) .nt-timeline-dot {
+  background-color: var(--nt-color-6);
+}
+
+.nt-timeline-item:nth-child(7) .nt-timeline-dot {
+  background-color: var(--nt-color-7);
+}
+
+.nt-timeline-item:nth-child(8) .nt-timeline-dot {
+  background-color: var(--nt-color-8);
+}
+
+.nt-timeline-item:nth-child(9) .nt-timeline-dot {
+  background-color: var(--nt-color-9);
+}
+
+.nt-timeline-item:nth-child(10) .nt-timeline-dot {
+  background-color: var(--nt-color-10);
+}
+
+.nt-timeline-item:nth-child(11) .nt-timeline-dot {
+  background-color: var(--nt-color-11);
+}
+
+.nt-timeline-item:nth-child(12) .nt-timeline-dot {
+  background-color: var(--nt-color-12);
+}
+
+.nt-timeline-item:nth-child(13) .nt-timeline-dot {
+  background-color: var(--nt-color-13);
+}
+
+.nt-timeline-item:nth-child(14) .nt-timeline-dot {
+  background-color: var(--nt-color-14);
+}
+
+.nt-timeline-item:nth-child(15) .nt-timeline-dot {
+  background-color: var(--nt-color-15);
+}
+
+.nt-timeline-item:nth-child(16) .nt-timeline-dot {
+  background-color: var(--nt-color-16);
+}
+
+.nt-timeline-item:nth-child(17) .nt-timeline-dot {
+  background-color: var(--nt-color-17);
+}
+
+.nt-timeline-item:nth-child(18) .nt-timeline-dot {
+  background-color: var(--nt-color-18);
+}
+
+.nt-timeline-item:nth-child(19) .nt-timeline-dot {
+  background-color: var(--nt-color-19);
+}
+
+.nt-timeline-item:nth-child(20) .nt-timeline-dot {
+  background-color: var(--nt-color-20);
+}
+
+/**
+ *  Extra CSS for the neoteroi.projects.gantt extension.
+ *
+ *  https://github.com/Neoteroi/mkdocs-plugins
+**/
+:root {
+  --nt-scrollbar-color: #2751b0;
+  --nt-plan-actions-height: 24px;
+  --nt-units-background: #ff9800;
+  --nt-months-background: #2751b0;
+  --nt-plan-vertical-line-color: #a3a3a3ad;
+}
+
+.nt-pastello {
+  --nt-scrollbar-color: #9fb8f4;
+  --nt-units-background: #f5dc82;
+  --nt-months-background: #5b7fd1;
+}
+
+[data-md-color-scheme=slate] {
+  --nt-units-background: #003773;
+}
+[data-md-color-scheme=slate] .nt-pastello {
+  --nt-units-background: #3f4997;
+}
+
+.nt-plan-root {
+  min-height: 200px;
+  scrollbar-width: 20px;
+  scrollbar-color: var(--nt-scrollbar-color);
+  display: flex;
+}
+.nt-plan-root ::-webkit-scrollbar {
+  width: 20px;
+}
+.nt-plan-root ::-webkit-scrollbar-track {
+  box-shadow: inset 0 0 5px grey;
+  border-radius: 10px;
+}
+.nt-plan-root ::-webkit-scrollbar-thumb {
+  background: var(--nt-scrollbar-color);
+  border-radius: 10px;
+}
+.nt-plan-root .nt-plan {
+  flex: 80%;
+}
+.nt-plan-root.no-groups .nt-plan-periods {
+  padding-left: 0;
+}
+.nt-plan-root.no-groups .nt-plan-group-summary {
+  display: none;
+}
+.nt-plan-root .nt-timeline-dot.bigger {
+  top: -10px;
+}
+.nt-plan-root .nt-timeline-dot.bigger[title] {
+  cursor: help;
+}
+
+.nt-plan {
+  white-space: nowrap;
+  overflow-x: auto;
+  display: flex;
+}
+.nt-plan .ug-timeline-dot {
+  left: 368px;
+  top: -8px;
+  cursor: help;
+}
+
+.months {
+  display: flex;
+}
+
+.month {
+  flex: auto;
+  display: inline-block;
+  box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 1px -2px, rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px inset;
+  background-color: var(--nt-months-background);
+  color: white;
+  text-transform: uppercase;
+  font-family: Roboto, Helvetica, Arial, sans-serif;
+  padding: 2px 5px;
+  font-size: 12px;
+  border: 1px solid #000;
+  width: 150px;
+  border-radius: 8px;
+}
+
+.nt-plan-group-activities {
+  flex: auto;
+  position: relative;
+}
+
+.nt-vline {
+  border-left: 1px dashed var(--nt-plan-vertical-line-color);
+  height: 100%;
+  left: 0;
+  position: absolute;
+  margin-left: -0.5px;
+  top: 0;
+  -webkit-transition: all 0.5s linear !important;
+  -moz-transition: all 0.5s linear !important;
+  -ms-transition: all 0.5s linear !important;
+  -o-transition: all 0.5s linear !important;
+  transition: all 0.5s linear !important;
+  z-index: -2;
+}
+
+.nt-plan-activity {
+  display: flex;
+  margin: 2px 0;
+  background-color: rgba(187, 187, 187, 0.2509803922);
+}
+
+.actions {
+  height: var(--nt-plan-actions-height);
+}
+
+.actions {
+  position: relative;
+}
+
+.period {
+  display: inline-block;
+  height: var(--nt-plan-actions-height);
+  width: 120px;
+  position: absolute;
+  left: 0px;
+  background: #1da1f2;
+  border-radius: 5px;
+  transition: all 0.5s;
+  cursor: help;
+  -webkit-transition: width 1s ease-in-out;
+  -moz-transition: width 1s ease-in-out;
+  -o-transition: width 1s ease-in-out;
+  transition: width 1s ease-in-out;
+}
+.period .nt-tooltip {
+  display: none;
+  top: 30px;
+  position: relative;
+  padding: 1rem;
+  text-align: center;
+  font-size: 12px;
+}
+.period:hover .nt-tooltip {
+  display: inline-block;
+}
+
+.period-0 {
+  left: 340px;
+  visibility: visible;
+  background-color: rgb(69, 97, 101);
+}
+
+.period-1 {
+  left: 40px;
+  visibility: visible;
+  background-color: green;
+}
+
+.period-2 {
+  left: 120px;
+  visibility: visible;
+  background-color: pink;
+  width: 80px;
+}
+
+.period-3 {
+  left: 190px;
+  visibility: visible;
+  background-color: darkred;
+  width: 150px;
+}
+
+.weeks > span,
+.days > span {
+  height: 25px;
+}
+
+.weeks > span {
+  display: inline-block;
+  margin: 0;
+  padding: 0;
+  font-weight: bold;
+}
+.weeks > span .week-text {
+  font-size: 10px;
+  position: absolute;
+  display: inline-block;
+  padding: 3px 4px;
+}
+
+.days {
+  z-index: -2;
+  position: relative;
+}
+
+.day-text {
+  font-size: 10px;
+  position: absolute;
+  display: inline-block;
+  padding: 3px 4px;
+}
+
+.period span {
+  font-size: 12px;
+  vertical-align: top;
+  margin-left: 4px;
+  color: black;
+  background: rgba(255, 255, 255, 0.6588235294);
+  border-radius: 6px;
+  padding: 0 4px;
+}
+
+.weeks,
+.days {
+  height: 20px;
+  display: flex;
+  box-sizing: content-box;
+}
+
+.months {
+  display: flex;
+}
+
+.week,
+.day {
+  height: 20px;
+  position: relative;
+  border: 1;
+  flex: auto;
+  border: 2px solid white;
+  border-radius: 4px;
+  background-color: var(--nt-units-background);
+  cursor: help;
+}
+
+.years {
+  display: flex;
+}
+
+.year {
+  text-align: center;
+  border-right: 1px solid var(--nt-plan-vertical-line-color);
+  font-weight: bold;
+}
+.year:first-child {
+  border-left: 1px solid var(--nt-plan-vertical-line-color);
+}
+.year:first-child:last-child {
+  width: 100%;
+}
+
+.quarters {
+  display: flex;
+}
+
+.quarter {
+  width: 12.5%;
+  text-align: center;
+  border-right: 1px solid var(--nt-plan-vertical-line-color);
+  font-weight: bold;
+}
+.quarter:first-child {
+  border-left: 1px solid var(--nt-plan-vertical-line-color);
+}
+
+.nt-plan-group {
+  margin: 20px 0;
+  position: relative;
+}
+
+.nt-plan-group {
+  display: flex;
+}
+
+.nt-plan-group-summary {
+  background: #2751b0;
+  width: 150px;
+  white-space: normal;
+  padding: 0.1rem 0.5rem;
+  border-radius: 5px;
+  color: #fff;
+  z-index: 3;
+}
+.nt-plan-group-summary p {
+  margin: 0;
+  padding: 0;
+  font-size: 0.6rem;
+  color: #fff;
+}
+
+.nt-plan-group-summary,
+.month,
+.period,
+.week,
+.day,
+.nt-tooltip {
+  border: 3px solid white;
+  box-shadow: 0 2px 3px -1px rgba(0, 0, 0, 0.2), 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+}
+
+.nt-plan-periods {
+  padding-left: 150px;
+}
+
+.months {
+  z-index: 2;
+  position: relative;
+}
+
+.weeks {
+  position: relative;
+  top: -2px;
+  z-index: 0;
+}
+
+.month,
+.quarter,
+.year,
+.week,
+.day,
+.nt-tooltip {
+  font-family: Roboto, Helvetica, Arial, sans-serif;
+  box-sizing: border-box;
+}
+
+.nt-cards.nt-grid {
+  display: grid;
+  grid-auto-columns: 1fr;
+  gap: 0.5rem;
+  max-width: 100vw;
+  overflow-x: auto;
+  padding: 1px;
+}
+.nt-cards.nt-grid.cols-1 {
+  grid-template-columns: repeat(1, 1fr);
+}
+.nt-cards.nt-grid.cols-2 {
+  grid-template-columns: repeat(2, 1fr);
+}
+.nt-cards.nt-grid.cols-3 {
+  grid-template-columns: repeat(3, 1fr);
+}
+.nt-cards.nt-grid.cols-4 {
+  grid-template-columns: repeat(4, 1fr);
+}
+.nt-cards.nt-grid.cols-5 {
+  grid-template-columns: repeat(5, 1fr);
+}
+.nt-cards.nt-grid.cols-6 {
+  grid-template-columns: repeat(6, 1fr);
+}
+
+@media only screen and (max-width: 400px) {
+  .nt-cards.nt-grid {
+    grid-template-columns: repeat(1, 1fr) !important;
+  }
+}
+.nt-card {
+  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+}
+.nt-card:hover {
+  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 3px 1px -2px rgba(0, 0, 0, 0.3), 0 1px 5px 0 rgba(0, 0, 0, 0.22);
+}
+
+[data-md-color-scheme=slate] .nt-card {
+  box-shadow: 0 2px 2px 0 rgba(4, 40, 33, 0.14), 0 3px 1px -2px rgba(40, 86, 94, 0.47), 0 1px 5px 0 rgba(139, 252, 255, 0.64);
+}
+[data-md-color-scheme=slate] .nt-card:hover {
+  box-shadow: 0 2px 2px 0 rgba(0, 255, 206, 0.14), 0 3px 1px -2px rgba(33, 156, 177, 0.47), 0 1px 5px 0 rgba(96, 251, 255, 0.64);
+}
+
+.nt-card > a {
+  color: var(--md-default-fg-color);
+}
+
+.nt-card > a > div {
+  cursor: pointer;
+}
+
+.nt-card {
+  padding: 5px;
+  margin-bottom: 0.5rem;
+}
+
+.nt-card-title {
+  font-size: 1rem;
+  font-weight: bold;
+  margin: 4px 0 8px 0;
+  line-height: 22px;
+}
+
+.nt-card-content {
+  padding: 0.4rem 0.8rem 0.8rem 0.8rem;
+}
+
+.nt-card-text {
+  font-size: 14px;
+  padding: 0;
+  margin: 0;
+}
+
+.nt-card .nt-card-image {
+  text-align: center;
+  border-radius: 2px;
+  background-position: center center;
+  background-size: cover;
+  background-repeat: no-repeat;
+  min-height: 120px;
+}
+
+.nt-card .nt-card-image.tags img {
+  margin-top: 12px;
+}
+
+.nt-card .nt-card-image img {
+  height: 105px;
+  margin-top: 5px;
+}
+
+.nt-card a:hover,
+.nt-card a:focus {
+  color: var(--md-accent-fg-color);
+}
+
+.nt-card h2 {
+  margin: 0;
+}
+
+/**
+ *   Extra CSS file recommended for MkDocs and neoteroi.spantable extension.
+ *
+ *   https://github.com/Neoteroi/mkdocs-plugins
+**/
+.span-table-wrapper table {
+  border-collapse: collapse;
+  margin-bottom: 2rem;
+  border-radius: 0.1rem;
+}
+
+.span-table td,
+.span-table th {
+  padding: 0.2rem;
+  background-color: var(--md-default-bg-color);
+  font-size: 0.64rem;
+  max-width: 100%;
+  overflow: auto;
+  touch-action: auto;
+  border-top: 0.05rem solid var(--md-typeset-table-color);
+  padding: 0.9375em 1.25em;
+  vertical-align: top;
+}
+
+.span-table tr:first-child td {
+  font-weight: 700;
+  min-width: 5rem;
+  padding: 0.9375em 1.25em;
+  vertical-align: top;
+}
+
+.span-table td:first-child {
+  border-left: 0.05rem solid var(--md-typeset-table-color);
+}
+
+.span-table td:last-child {
+  border-right: 0.05rem solid var(--md-typeset-table-color);
+}
+
+.span-table tr:last-child {
+  border-bottom: 0.05rem solid var(--md-typeset-table-color);
+}
+
+.span-table [colspan],
+.span-table [rowspan] {
+  font-weight: bold;
+  border: 0.05rem solid var(--md-typeset-table-color);
+}
+
+.span-table tr:not(:first-child):hover td:not([colspan]):not([rowspan]),
+.span-table td[colspan]:hover,
+.span-table td[rowspan]:hover {
+  background-color: rgba(0, 0, 0, 0.035);
+  box-shadow: 0 0.05rem 0 var(--md-default-bg-color) inset;
+  transition: background-color 125ms;
+}
diff --git a/docs/extract_schema.py b/docs/extract_schema.py
new file mode 100644
index 0000000000..95f99d0c66
--- /dev/null
+++ b/docs/extract_schema.py
@@ -0,0 +1,232 @@
+"""Extract API schema and split into smaller subsections."""
+
+import argparse
+import os
+import re
+import textwrap
+
+import yaml
+
+OUTPUT_DIR = './docs/api/schema/'
+
+# General path
+GENERAL_PATH = 'general'
+
+# List of special paths we want to split out
+SPECIAL_PATHS = {
+    'auth': 'Authorization and Authentication',
+    'background-task': 'Background Task Management',
+    'barcode': 'Barcode Scanning',
+    'bom': 'Bill of Materials',
+    'build': 'Build Order Management',
+    'company': 'Company Management',
+    'label': 'Label Printing',
+    'machine': 'External Machine Management',
+    'order': 'External Order Management',
+    'part': 'Parts and Part Categories',
+    'plugins': 'Plugin Functionality',
+    'report': 'Report Generation',
+    'settings': 'Settings Management',
+    'stock': 'Stock and Stock Locations',
+    'user': 'User Management',
+}
+
+
+def top_level_path(path: str) -> str:
+    """Return the top level path of the input path."""
+    path = path.strip()
+
+    if path.startswith('/'):
+        path = path[1:]
+
+    if path.endswith('/'):
+        path = path[:-1]
+
+    path = path.strip()
+
+    key = path.split('/')[1]
+
+    if key in SPECIAL_PATHS.keys():
+        return key
+
+    return GENERAL_PATH
+
+
+def generate_schema_file(key: str) -> None:
+    """Generate a schema file for the provided key."""
+    description = (
+        SPECIAL_PATHS[key] if key in SPECIAL_PATHS else 'General API Endpoints'
+    )
+
+    output = f"""
+    ---
+    title: {description}
+    ---
+
+    The *{description}* section of the InvenTree API schema is documented below.
+
+    [OAD(./docs/docs/api/schema/{key}.yml)]
+    """
+
+    output = textwrap.dedent(output).strip() + '\n'
+
+    output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, f'{key}.md')
+    output_file = os.path.abspath(output_file)
+
+    print('Writing schema file to:', output_file)
+
+    with open(output_file, 'w') as f:
+        f.write(output)
+
+
+def generate_index_file(version: str):
+    """Generate the index file for the API schema."""
+    output = f"""
+    ---
+    title: InvenTree API Schema
+    ---
+
+    The InvenTree API is implemented using the [Django REST framework](https://www.django-rest-framework.org).
+    The API schema as documented below is generated using the [drf-spectactular](https://github.com/tfranzel/drf-spectacular/) extension.
+
+    ## API Version
+
+    This documentation is for API version: `{version}`
+
+    !!! tip "API Schema History"
+        We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/).
+
+    ## API Schema File
+
+    The API schema file is available for download, and can be used for generating client libraries, or for testing API endpoints.
+
+    ## API Schema Documentation
+
+    API schema documentation is split into the following categories:
+
+    | Category | Description |
+    | --- | --- |
+    """
+
+    output = textwrap.dedent(output).strip() + '\n'
+
+    for key, value in SPECIAL_PATHS.items():
+        output += f'| [{value}](./schema/{key}.md) | {value} |\n'
+
+    output += '| [General](./schema/general.md) | General API endpoints |\n'
+
+    output += '\n'
+
+    output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, '..', 'schema.md')
+
+    print('Writing index file to:', output_file)
+
+    with open(output_file, 'w') as f:
+        f.write(output)
+
+
+def extract_refs(data: dict, components: dict) -> list:
+    """Extract a list of refs from the provided paths dict.
+
+    The refs are located like so:
+    <path>:<method>:responses:<status>:content:application/json:schema:$ref
+
+    Also, the referenced components might reference *sub* components,
+    so we need to do this step recursively.
+
+    """
+    pattern = r"'?\$ref'?: '#\/components\/schemas\/(\S+)'"
+
+    # First, extract the results from the paths data dict
+    matches = re.findall(pattern, str(data))
+
+    refs = list(matches)
+
+    # Next, extract additional refs from the components dict
+    # Note that the components dict may reference other components
+
+    idx = 0
+
+    while idx < len(refs):
+        ref = refs[idx]
+
+        schema = components.get('schemas', {}).get(ref, None)
+
+        if schema:
+            # Search for additional refs
+            matches = re.findall(pattern, str(schema))
+
+            for match in matches:
+                if match not in refs:
+                    refs.append(match)
+
+        idx += 1
+
+    # Return a dict only of the extracted refs
+    schemas = {ref: components['schemas'][ref] for ref in refs}
+
+    return schemas
+
+
+def parse_api_file(filename: str):
+    """Parse the input API file, and split into smaller sections.
+
+    The intent is to make the API schema easier to peruse on the documentation.
+    """
+    with open(filename, 'r') as f:
+        data = yaml.safe_load(f)
+
+    paths = data['paths']
+
+    top_level_paths = {}
+
+    for path, methods in paths.items():
+        tlp = top_level_path(path)
+
+        if tlp not in top_level_paths:
+            top_level_paths[tlp] = {}
+
+        top_level_paths[tlp][path] = methods
+
+    # Generate output files
+    for key, value in top_level_paths.items():
+        output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, f'{key}.yml')
+
+        output = {}
+
+        output['paths'] = value
+
+        components = data.get('components', {})
+
+        # Extract only the schemas relating to the provided paths
+        path_schemas = extract_refs(value, components)
+
+        for k, v in data.items():
+            if k == 'components':
+                v = v.copy()
+                v['schemas'] = path_schemas
+
+            if k != 'paths':
+                output[k] = v
+
+        print(f'Writing schema file to {output_file}...')
+
+        output_file = os.path.abspath(output_file)
+
+        with open(output_file, 'w') as f:
+            yaml.dump(output, f)
+
+        # Generate a markdown file for the schema
+        generate_schema_file(key)
+
+    # Finally, generate an index file for the API schema
+    generate_index_file(data['info']['version'])
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('input', help='Input API schema file (.yml)')
+
+    args = parser.parse_args()
+
+    parse_api_file(args.input)
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index 9de602d7ea..0ed500b342 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -57,6 +57,7 @@ extra_css:
   - stylesheets/bootstrap.css
   - stylesheets/splide.min.css
   - stylesheets/extra.css
+  - stylesheets/neoteroi-mkdocs.css
 extra_javascript:
   - javascripts/extra.js
   - javascripts/fontawesome.js
@@ -182,6 +183,7 @@ nav:
   - Extend:
     - InvenTree API:
       - Overview: api/api.md
+      - API Schema: api/schema.md
       - Model Metadata: api/metadata.md
       - Download Data: api/download.md
       - Bulk Delete: api/bulk_delete.md
@@ -225,6 +227,8 @@ nav:
 
 # Plugins
 plugins:
+  - neoteroi.mkdocsoad:
+      use_pymdownx: true
   - include-markdown:
       opening_tag: "{!"
       closing_tag: "!}"
@@ -252,6 +256,8 @@ markdown_extensions:
   - meta
   - pymdownx.details
   - pymdownx.highlight
+  - pymdownx.tabbed:
+      alternate_style: true
   - pymdownx.superfences:
       custom_fences:
         - name: mermaid
diff --git a/docs/requirements.txt b/docs/requirements.txt
index b7290b79f2..6e85d3a92f 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -4,4 +4,5 @@ mkdocs-material>=9.0,<10.0
 mkdocs-git-revision-date-localized-plugin>=1.1,<2.0
 mkdocs-simple-hooks>=0.1,<1.0
 mkdocs-include-markdown-plugin
+neoteroi-mkdocs
 mkdocstrings[python]>=0.24.0
diff --git a/readthedocs.yml b/readthedocs.yml
index cd0eb5f01b..f9c578d243 100644
--- a/readthedocs.yml
+++ b/readthedocs.yml
@@ -6,8 +6,16 @@ mkdocs:
 python:
   install:
     - requirements: docs/requirements.txt
+    - requirements: requirements.txt
 
 build:
   os: "ubuntu-22.04"
   tools:
     python: "3.9"
+  jobs:
+    post_install:
+      - echo "Generating API schema file"
+      - pip install -U invoke
+      - invoke migrate
+      - invoke schema --filename docs/schema.yml --ignore-warnings
+      - python docs/extract_schema.py docs/schema.yml
diff --git a/tasks.py b/tasks.py
index dca41d4755..2c2b56089b 100644
--- a/tasks.py
+++ b/tasks.py
@@ -918,6 +918,10 @@ def schema(c, filename='schema.yml', overwrite=False, ignore_warnings=False):
     """Export current API schema."""
     check_file_existance(filename, overwrite)
 
+    filename = os.path.abspath(filename)
+
+    print(f"Exporting schema file to '{filename}'")
+
     cmd = f'spectacular --file {filename} --validate --color'
 
     if not ignore_warnings:
@@ -925,6 +929,10 @@ def schema(c, filename='schema.yml', overwrite=False, ignore_warnings=False):
 
     manage(c, cmd, pty=True)
 
+    assert os.path.exists(filename)
+
+    print('Schema export completed:', filename)
+
 
 @task(default=True)
 def version(c):