diff --git a/assets/js/resizable-panels.js b/assets/js/resizable-panels.js
new file mode 100644
index 0000000000..388e12c0b7
--- /dev/null
+++ b/assets/js/resizable-panels.js
@@ -0,0 +1,259 @@
+/**
+ * Resizable Panels Feature
+ * Allows users to adjust the width of side panels (left sidebar and right TOC)
+ * Preferences are saved to localStorage and restored on page load
+ * Includes reset functionality to restore default widths
+ */
+
+(function() {
+ 'use strict';
+
+ const STORAGE_KEY = 'layer5-docs-panel-widths';
+ const DEFAULT_WIDTHS = {
+ sidebar: 2, // col-xl-2 = ~16.66%
+ toc: 2, // col-xl-2 = ~16.66%
+ main: 8 // col-xl-8 = ~66.66%
+ };
+
+ // CSS class shortcuts for Bootstrap grid columns
+ const COL_CLASSES = {
+ 'col-1': 8.33,
+ 'col-2': 16.66,
+ 'col-3': 25,
+ 'col-4': 33.33,
+ 'col-5': 41.66,
+ 'col-6': 50,
+ 'col-7': 58.33,
+ 'col-8': 66.66,
+ 'col-9': 75,
+ 'col-10': 83.33,
+ 'col-11': 91.66,
+ 'col-12': 100
+ };
+
+ class ResizablePanels {
+ constructor() {
+ this.sidebar = document.querySelector('.td-sidebar');
+ this.toc = document.querySelector('.td-sidebar-toc');
+ this.main = document.querySelector('main[role="main"]');
+ this.row = document.querySelector('.row.flex-xl-nowrap');
+
+ if (!this.row || !this.sidebar || !this.main) {
+ console.warn('Resizable panels: Required elements not found');
+ return;
+ }
+
+ this.isResizing = false;
+ this.currentResizeTarget = null;
+ this.startX = 0;
+ this.startWidth = 0;
+
+ this.init();
+ }
+
+ init() {
+ // Load saved widths from localStorage
+ this.loadSavedWidths();
+
+ // Create resize handles
+ this.createResizeHandles();
+
+ // Add event listeners
+ this.addEventListeners();
+
+ // Add reset button
+ this.addResetButton();
+ }
+
+ loadSavedWidths() {
+ try {
+ const saved = localStorage.getItem(STORAGE_KEY);
+ if (saved) {
+ const widths = JSON.parse(saved);
+ this.applyWidths(widths);
+ }
+ } catch (error) {
+ console.error('Error loading saved panel widths:', error);
+ }
+ }
+
+ createResizeHandles() {
+ // Create resize handle between sidebar and main content
+ const sidebarHandle = document.createElement('div');
+ sidebarHandle.className = 'resizable-panel-handle resizable-panel-handle--right';
+ sidebarHandle.setAttribute('data-resize-target', 'sidebar');
+ sidebarHandle.setAttribute('title', 'Drag to resize sidebar');
+ this.sidebar.appendChild(sidebarHandle);
+
+ // Create resize handle for TOC (if it exists)
+ if (this.toc) {
+ const tocHandle = document.createElement('div');
+ tocHandle.className = 'resizable-panel-handle resizable-panel-handle--left';
+ tocHandle.setAttribute('data-resize-target', 'toc');
+ tocHandle.setAttribute('title', 'Drag to resize table of contents');
+ this.toc.appendChild(tocHandle);
+ }
+ }
+
+ addEventListeners() {
+ document.addEventListener('mousedown', (e) => this.onMouseDown(e));
+ document.addEventListener('mousemove', (e) => this.onMouseMove(e));
+ document.addEventListener('mouseup', (e) => this.onMouseUp(e));
+ }
+
+ onMouseDown(e) {
+ if (!e.target.classList.contains('resizable-panel-handle')) {
+ return;
+ }
+
+ this.isResizing = true;
+ this.currentResizeTarget = e.target.getAttribute('data-resize-target');
+ this.startX = e.clientX;
+
+ // Store current widths for delta calculation
+ this.startWidths = this.getCurrentWidths();
+
+ // Add active state
+ e.target.classList.add('resizable-panel-handle--active');
+ document.body.style.userSelect = 'none';
+ document.body.style.cursor = 'col-resize';
+ }
+
+ onMouseMove(e) {
+ if (!this.isResizing) return;
+
+ const delta = e.clientX - this.startX;
+ const adjustment = delta / window.innerWidth; // Convert pixels to percentage-like ratio
+
+ let newWidths = { ...this.startWidths };
+
+ if (this.currentResizeTarget === 'sidebar') {
+ // Resizing left sidebar
+ const sidebarPercent = (this.startWidths.sidebar * 100) / 12; // Convert col units to percentage
+ const mainPercent = (this.startWidths.main * 100) / 12;
+
+ const newSidebarPercent = sidebarPercent + (adjustment * 100);
+ const newMainPercent = mainPercent - (adjustment * 100);
+
+ // Constrain widths: min 1 col, max 5 cols for sidebar; min 4 cols for main
+ if (newSidebarPercent >= 8.33 && newSidebarPercent <= 41.66 && newMainPercent >= 33.33) {
+ newWidths.sidebar = Math.round((newSidebarPercent / 100) * 12);
+ newWidths.main = Math.round((newMainPercent / 100) * 12);
+ }
+ } else if (this.currentResizeTarget === 'toc') {
+ // Resizing right TOC panel
+ const tocPercent = (this.startWidths.toc * 100) / 12;
+ const mainPercent = (this.startWidths.main * 100) / 12;
+
+ const newTocPercent = tocPercent - (adjustment * 100);
+ const newMainPercent = mainPercent + (adjustment * 100);
+
+ // Constrain widths: min 1 col, max 5 cols for toc; min 4 cols for main
+ if (newTocPercent >= 8.33 && newTocPercent <= 41.66 && newMainPercent >= 33.33) {
+ newWidths.toc = Math.round((newTocPercent / 100) * 12);
+ newWidths.main = Math.round((newMainPercent / 100) * 12);
+ }
+ }
+
+ this.applyWidths(newWidths);
+ }
+
+ onMouseUp(e) {
+ if (!this.isResizing) return;
+
+ this.isResizing = false;
+ const handle = document.querySelector('.resizable-panel-handle--active');
+ if (handle) {
+ handle.classList.remove('resizable-panel-handle--active');
+ }
+
+ document.body.style.userSelect = '';
+ document.body.style.cursor = '';
+
+ // Save widths to localStorage
+ this.savePanelWidths();
+ }
+
+ applyWidths(widths) {
+ const { sidebar, toc, main } = widths;
+
+ // Update sidebar
+ this.removeBootstrapColClasses(this.sidebar);
+ this.sidebar.classList.add(`col-xl-${sidebar}`);
+
+ // Update main
+ this.removeBootstrapColClasses(this.main);
+ this.main.classList.add(`col-xl-${main}`);
+
+ // Update TOC if it exists
+ if (this.toc) {
+ this.removeBootstrapColClasses(this.toc);
+ this.toc.classList.add(`col-xl-${toc}`);
+ }
+ }
+
+ getCurrentWidths() {
+ const getColNumber = (element) => {
+ const classes = element.className.split(' ');
+ const colClass = classes.find(c => c.match(/col-xl-\d+/));
+ return colClass ? parseInt(colClass.split('-')[2]) : null;
+ };
+
+ return {
+ sidebar: getColNumber(this.sidebar) || DEFAULT_WIDTHS.sidebar,
+ toc: this.toc ? (getColNumber(this.toc) || DEFAULT_WIDTHS.toc) : DEFAULT_WIDTHS.toc,
+ main: getColNumber(this.main) || DEFAULT_WIDTHS.main
+ };
+ }
+
+ removeBootstrapColClasses(element) {
+ const classes = element.className.split(' ').filter(c => !c.match(/col-xl-\d+/));
+ element.className = classes.join(' ').trim();
+ }
+
+ savePanelWidths() {
+ try {
+ const widths = this.getCurrentWidths();
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(widths));
+ } catch (error) {
+ console.error('Error saving panel widths:', error);
+ }
+ }
+
+ addResetButton() {
+ // Find the feature-info-container or page-header to add reset button
+ const pageHeader = document.querySelector('.page-header');
+ if (!pageHeader) return;
+
+ const resetButton = document.createElement('button');
+ resetButton.id = 'reset-panel-widths';
+ resetButton.className = 'btn btn-sm btn-outline-secondary ms-2';
+ resetButton.innerHTML = ' Reset Layout';
+ resetButton.setAttribute('title', 'Reset panel widths to default');
+
+ resetButton.addEventListener('click', () => this.resetPanelWidths());
+
+ // Find a good place to insert the button
+ const featureContainer = pageHeader.querySelector('.feature-info-container');
+ if (featureContainer) {
+ featureContainer.insertAdjacentElement('beforeend', resetButton);
+ } else {
+ pageHeader.insertAdjacentElement('beforeend', resetButton);
+ }
+ }
+
+ resetPanelWidths() {
+ this.applyWidths(DEFAULT_WIDTHS);
+ this.savePanelWidths();
+ }
+ }
+
+ // Initialize when DOM is ready
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => {
+ new ResizablePanels();
+ });
+ } else {
+ new ResizablePanels();
+ }
+})();
diff --git a/assets/scss/_kanvas-corner-popup.scss b/assets/scss/_kanvas-corner-popup.scss
index bc3022f84f..fc5b4da715 100644
--- a/assets/scss/_kanvas-corner-popup.scss
+++ b/assets/scss/_kanvas-corner-popup.scss
@@ -57,7 +57,7 @@
padding: 1rem;
border: 1px solid #00d3a9;
border-radius: 5%;
- box-shadow: 0 0 42px rgba(0, 211, 169, 0.85), 0 0 80px rgba(0, 211, 169, 0.25);
+ box-shadow: 0 0 28px rgba(0, 211, 169, 0.55);
@media (max-width: 640px) {
padding: 0.8rem;
diff --git a/assets/scss/_resizable-panels.scss b/assets/scss/_resizable-panels.scss
new file mode 100644
index 0000000000..3311227f9a
--- /dev/null
+++ b/assets/scss/_resizable-panels.scss
@@ -0,0 +1,147 @@
+/**
+ * Resizable Panels Styling
+ * Styles for the resize handles and drag interactions
+ */
+
+// Resize handle styling
+.resizable-panel-handle {
+ position: absolute;
+ background-color: transparent;
+ transition: background-color 0.2s ease;
+ z-index: 100;
+
+ &--right {
+ // Right edge handle (between sidebar and main)
+ right: -3px;
+ top: 0;
+ bottom: 0;
+ width: 6px;
+ cursor: col-resize;
+ background-color: rgba(0, 211, 169, 0.15);
+
+ &:hover,
+ &--active {
+ background-color: rgba(0, 211, 169, 0.4);
+
+ &::after {
+ opacity: 1;
+ }
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ right: 1px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 3px;
+ height: 50px;
+ background-color: #00d3a9;
+ opacity: 0.3;
+ transition: opacity 0.2s ease;
+ border-radius: 2px;
+ box-shadow: 0 0 4px rgba(0, 211, 169, 0.5);
+ }
+ }
+
+ &--left {
+ // Left edge handle (between main and TOC)
+ left: -3px;
+ top: 0;
+ bottom: 0;
+ width: 6px;
+ cursor: col-resize;
+ background-color: rgba(0, 211, 169, 0.15);
+
+ &:hover,
+ &--active {
+ background-color: rgba(0, 211, 169, 0.4);
+
+ &::after {
+ opacity: 1;
+ }
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ left: 1px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 3px;
+ height: 50px;
+ background-color: #00d3a9;
+ opacity: 0.3;
+ transition: opacity 0.2s ease;
+ border-radius: 2px;
+ box-shadow: 0 0 4px rgba(0, 211, 169, 0.5);
+ }
+ }
+
+ &--active {
+ background-color: rgba(0, 211, 169, 0.5);
+ }
+}
+
+// Reset button styling
+#reset-panel-widths {
+ white-space: nowrap;
+ font-size: 0.875rem;
+
+ i {
+ margin-right: 0.25rem;
+ }
+
+ &:hover {
+ background-color: #00d3a9;
+ color: #fff;
+ }
+}
+
+// Make panels relatively positioned for absolute handle positioning
+.td-sidebar,
+.td-sidebar-toc {
+ position: relative;
+}
+
+// Ensure sidebar nav has proper scrolling with resizable panels
+.td-sidebar-nav {
+ padding-bottom: 2rem;
+}
+
+// Smooth transitions for width changes
+.td-sidebar,
+.td-sidebar-toc,
+main[role="main"] {
+ transition: flex-basis 0.3s ease;
+}
+
+// Ensure row is flex container for proper layout
+.row.flex-xl-nowrap {
+ display: flex;
+ flex-wrap: nowrap;
+
+ > aside,
+ > main {
+ overflow-x: hidden;
+ }
+}
+
+// Mobile/Tablet adjustments - disable resize handles on smaller screens
+@media (max-width: 1199.98px) {
+ .resizable-panel-handle {
+ display: none;
+ }
+
+ #reset-panel-widths {
+ display: none;
+ }
+}
+
+// Print styles - hide resize handles
+@media print {
+ .resizable-panel-handle,
+ #reset-panel-widths {
+ display: none !important;
+ }
+}
diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss
index 00ca1b8770..84a003f563 100644
--- a/assets/scss/_styles_project.scss
+++ b/assets/scss/_styles_project.scss
@@ -15,6 +15,7 @@
@import "elements_project";
@import "summary.scss";
@import "_kanvas-corner-popup.scss";
+@import "_resizable-panels.scss";
.navbar-dark {
min-height: 5rem;
diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html
new file mode 100644
index 0000000000..409b2634f5
--- /dev/null
+++ b/layouts/partials/scripts.html
@@ -0,0 +1,16 @@
+
+
+{{ $kanvasTransition := resources.Get "js/kanvas-architectural-transition.js" -}}
+{{ if $kanvasTransition }}
+
+{{ end -}}
+
+{{ $kanvasPopup := resources.Get "js/kanvas-corner-popup.js" -}}
+{{ if $kanvasPopup }}
+
+{{ end -}}
+
+{{ $offlineSearch := resources.Get "js/offline-search.js" -}}
+{{ if $offlineSearch }}
+
+{{ end -}}