diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css
index 28db943..c55c757 100644
--- a/doc/source/_static/custom.css
+++ b/doc/source/_static/custom.css
@@ -42,6 +42,89 @@ body, .wy-body-for-nav {
background: var(--bg-2) !important;
border-right: 1px solid var(--rule);
}
+
+/* Desktop/tablet sidebar toggle. sphinx_rtd_theme owns the <=768px off-canvas
+ * menu, so these rules deliberately start at 769px. */
+.forge-sidebar-toggle {
+ display: none;
+}
+
+@media screen and (min-width: 769px) {
+ .wy-nav-side,
+ .wy-nav-content-wrap,
+ .forge-sidebar-toggle {
+ transition:
+ transform 160ms ease,
+ margin-left 160ms ease,
+ left 160ms ease;
+ }
+
+ .forge-sidebar-toggle {
+ align-items: center;
+ background: var(--bg-2);
+ border: 1px solid var(--rule);
+ border-left: 0;
+ border-radius: 0 4px 4px 0;
+ color: var(--fg-dim);
+ display: flex;
+ height: 48px;
+ justify-content: center;
+ left: 300px;
+ padding: 0;
+ position: fixed;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 28px;
+ z-index: 201;
+ }
+
+ .forge-sidebar-toggle:hover {
+ background: var(--bg-3);
+ color: var(--amber);
+ }
+
+ .forge-sidebar-toggle:focus-visible {
+ color: var(--amber);
+ outline: 2px solid var(--amber);
+ outline-offset: 2px;
+ }
+
+ .forge-sidebar-toggle-label {
+ clip: rect(0 0 0 0);
+ clip-path: inset(50%);
+ height: 1px;
+ overflow: hidden;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ }
+
+ html.forge-sidebar-collapsed .wy-nav-side {
+ transform: translateX(-100%);
+ }
+
+ html.forge-sidebar-collapsed .wy-nav-content-wrap {
+ margin-left: 0;
+ }
+
+ html.forge-sidebar-collapsed .wy-nav-content {
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ html.forge-sidebar-collapsed .forge-sidebar-toggle {
+ left: 0;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .wy-nav-side,
+ .wy-nav-content-wrap,
+ .forge-sidebar-toggle {
+ transition: none;
+ }
+}
+
.wy-side-nav-search {
background: var(--bg) !important;
border-bottom: 1px solid var(--rule);
diff --git a/doc/source/_static/sidebar.js b/doc/source/_static/sidebar.js
new file mode 100644
index 0000000..f4501f4
--- /dev/null
+++ b/doc/source/_static/sidebar.js
@@ -0,0 +1,100 @@
+// Hideable desktop/tablet navigation for sphinx_rtd_theme.
+//
+// The theme already provides an off-canvas hamburger at <=768px. Above that,
+// default to a reading-first layout on narrower screens while remembering an
+// explicit user choice across documentation pages.
+(function () {
+ 'use strict';
+
+ var STORAGE_KEY = 'forge-docs-sidebar';
+ var COLLAPSED_CLASS = 'forge-sidebar-collapsed';
+ var desktopMedia = window.matchMedia('(min-width: 769px)');
+ var narrowDesktopMedia = window.matchMedia('(max-width: 1099px)');
+ var root = document.documentElement;
+
+ function readPreference() {
+ try {
+ var value = window.localStorage.getItem(STORAGE_KEY);
+ return value === 'collapsed' || value === 'expanded' ? value : null;
+ } catch (_) {
+ return null;
+ }
+ }
+
+ function writePreference(value) {
+ try {
+ window.localStorage.setItem(STORAGE_KEY, value);
+ } catch (_) {
+ // Storage can be disabled; the toggle should still work for this page.
+ }
+ }
+
+ function shouldCollapse() {
+ if (!desktopMedia.matches) return false;
+ var preference = readPreference();
+ if (preference) return preference === 'collapsed';
+ return narrowDesktopMedia.matches;
+ }
+
+ // Apply the initial class before deferred DOM setup to avoid a visible
+ // sidebar jump on reading-first tablet/narrow-desktop layouts.
+ root.classList.toggle(COLLAPSED_CLASS, shouldCollapse());
+
+ function init() {
+ var navigation = document.querySelector('.wy-nav-side');
+ var toggle = document.querySelector('.forge-sidebar-toggle');
+ if (!navigation || !toggle) return;
+
+ navigation.id = 'forge-site-navigation';
+
+ var icon = toggle.querySelector('.fa');
+ var label = toggle.querySelector('.forge-sidebar-toggle-label');
+
+ function updateToggle() {
+ var collapsed = root.classList.contains(COLLAPSED_CLASS);
+ toggle.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
+ toggle.setAttribute(
+ 'title',
+ collapsed ? 'Show navigation' : 'Hide navigation'
+ );
+ if (label) {
+ label.textContent = collapsed ? 'Show navigation' : 'Hide navigation';
+ }
+ if (icon) {
+ icon.classList.toggle('fa-chevron-left', !collapsed);
+ icon.classList.toggle('fa-chevron-right', collapsed);
+ }
+ }
+
+ function syncLayout() {
+ root.classList.toggle(COLLAPSED_CLASS, shouldCollapse());
+ if (!desktopMedia.matches) {
+ // Always enter mobile with the theme's off-canvas menu closed.
+ document
+ .querySelectorAll("[data-toggle='wy-nav-shift']")
+ .forEach(function (element) {
+ element.classList.remove('shift');
+ });
+ }
+ updateToggle();
+ }
+
+ toggle.addEventListener('click', function () {
+ if (!desktopMedia.matches) return;
+ var collapsed = !root.classList.contains(COLLAPSED_CLASS);
+ root.classList.toggle(COLLAPSED_CLASS, collapsed);
+ writePreference(collapsed ? 'collapsed' : 'expanded');
+ updateToggle();
+ });
+
+ desktopMedia.addEventListener('change', syncLayout);
+ narrowDesktopMedia.addEventListener('change', syncLayout);
+ syncLayout();
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+})();
diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html
index 8e4c7b9..96fbae4 100644
--- a/doc/source/_templates/layout.html
+++ b/doc/source/_templates/layout.html
@@ -1,5 +1,19 @@
{%- extends "!layout.html" %}
+{# Desktop/tablet navigation toggle. The RTD theme supplies its own off-canvas
+ hamburger below 769px; this control is hidden there. sidebar.js adds the
+ controlled navigation id and keeps the accessible label/state in sync. #}
+{%- block extrabody %}
+ {{ super() }}
+
+{%- endblock %}
+
{# Override sphinx_rtd_theme's sidebar brand so the logo links to the
daslang.io home page instead of pathto(_root_doc). Mirrors the upstream
block at sphinx_rtd_theme/layout.html sidebartitle, with the
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 6a3d3ad..68174a5 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -73,4 +73,6 @@
# the daslang docs theme evolves.
html_css_files = ['custom.css', 'custom-patch.css']
+html_js_files = ['sidebar.js']
+
htmlhelp_basename = 'dasimguiimplot_doc'