Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/source/_static/css/mobile-menu-fix.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Mobile menu fix: ensure overlay is clickable on iOS */

/* Raise the stacked navigation elements above possible overlays */
.primary-toggle,
.secondary-toggle,
.mobile-menu-container .navbar,
.mobile-menu-container .navbar-collapse,
#pst-primary-sidebar-modal,
#pst-secondary-sidebar-modal {
z-index: 1500;
pointer-events: auto !important;
}

/*
* Ensure the modal overlay allows pointer events to reach menu links.
* Both `pointer-events: auto` and a high `z-index` are necessary because:
* - Some themes/modal implementations use overlays that block pointer events or stack above menu links,
* making them unclickable (especially on iOS).
* - This rule ensures that the backdrop does not block interaction with menu links,
* and that the stacking order is correct so links remain accessible.
* If the theme/modal implementation changes, review whether this workaround is still needed.
*/
.pst-modal-backdrop {
pointer-events: auto !important;
}
30 changes: 30 additions & 0 deletions docs/source/_static/js/mobile-menu-fix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Mobile menu fix: make touch interactions on mobile (iOS/Safari) reliably trigger
// the mobile navigation toggle. Minimal, defensive enhancement.
document.addEventListener('DOMContentLoaded', function () {
try {
const selectors = [
'.primary-toggle',
'.secondary-toggle',
'[data-toggle="collapse"]',
'.navbar [aria-controls][aria-expanded]'
].join(',');
const controls = Array.from(document.querySelectorAll(selectors));
controls.forEach(el => {
if (el.__pymc_touchbound) return;
el.__pymc_touchbound = true;
el.addEventListener('touchstart', function (e) {
// iOS sometimes doesn't synthesize click events for transformed
// elements or elements in certain stacking contexts. Best-effort
// bridge: prevent default then dispatch a MouseEvent click.
try {
// e.preventDefault(); // Removed to allow scrolling on touch devices
this.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The synthetic MouseEvent dispatched here may bypass accessibility features that screen readers and assistive technologies rely on. Touch events are properly exposed to accessibility APIs, but synthetic click events might not be. Consider testing with VoiceOver (iOS) or TalkBack (Android) to ensure users with screen readers can still navigate the menu, or add explicit ARIA live region announcements when the menu state changes.

Copilot uses AI. Check for mistakes.
} catch (err) {
// ignore errors
}
}, { passive: false });
});
} catch (err) {
// swallow errors to avoid breaking docs
}
});
11 changes: 10 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,16 @@ def setup(app):
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["../logos"]
html_static_path = [
"../logos",
"_static",
]
html_css_files = [
"css/mobile-menu-fix.css",
]
html_js_files = [
"js/mobile-menu-fix.js",
]

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
Expand Down