diff --git a/neode-ui/index.html b/neode-ui/index.html
index a486583f..c0e2ceb1 100644
--- a/neode-ui/index.html
+++ b/neode-ui/index.html
@@ -14,6 +14,8 @@
+
+
diff --git a/neode-ui/src/components/AppSwitcher.vue b/neode-ui/src/components/AppSwitcher.vue
index 0bf5d32a..a3db347b 100644
--- a/neode-ui/src/components/AppSwitcher.vue
+++ b/neode-ui/src/components/AppSwitcher.vue
@@ -104,11 +104,11 @@ function handleClickOutside(e: MouseEvent) {
}
onMounted(() => {
- document.addEventListener('click', handleClickOutside)
+ document.addEventListener('pointerdown', handleClickOutside)
})
onBeforeUnmount(() => {
- document.removeEventListener('click', handleClickOutside)
+ document.removeEventListener('pointerdown', handleClickOutside)
})
diff --git a/neode-ui/src/components/IdentityPicker.vue b/neode-ui/src/components/IdentityPicker.vue
index 4fdc892e..d42e8411 100644
--- a/neode-ui/src/components/IdentityPicker.vue
+++ b/neode-ui/src/components/IdentityPicker.vue
@@ -131,10 +131,10 @@ async function loadIdentities() {
onMounted(() => {
loadIdentities()
- document.addEventListener('click', onClickOutside)
+ document.addEventListener('pointerdown', onClickOutside)
})
onBeforeUnmount(() => {
- document.removeEventListener('click', onClickOutside)
+ document.removeEventListener('pointerdown', onClickOutside)
})
diff --git a/neode-ui/src/style.css b/neode-ui/src/style.css
index d17b1302..eaa2ceb8 100644
--- a/neode-ui/src/style.css
+++ b/neode-ui/src/style.css
@@ -2,6 +2,22 @@
@tailwind components;
@tailwind utilities;
+/* The app is dark-only — NEVER let the OS/browser theme leak into native
+ controls. Without this, select popups / scrollbars / date pickers follow
+ the user's OS setting (a light-mode ThinkPad rendered white dropdown
+ lists inside the dark UI, 2026-07-22). color-scheme pins Chromium's
+ native select popup dark; the explicit select/option rules cover
+ Firefox and the closed control itself. */
+:root {
+ color-scheme: dark;
+}
+select,
+select option,
+select optgroup {
+ background-color: #16181d;
+ color: #fff;
+}
+
/* Montserrat - header font (used in neode present) */
@font-face {
font-family: 'Montserrat';
diff --git a/neode-ui/src/views/Mesh.vue b/neode-ui/src/views/Mesh.vue
index 10bdac71..64902469 100644
--- a/neode-ui/src/views/Mesh.vue
+++ b/neode-ui/src/views/Mesh.vue
@@ -350,7 +350,7 @@ function updateKeyboardInset() {
onMounted(async () => {
window.addEventListener('resize', handleResize)
- document.addEventListener('click', handleDocClickForMenu)
+ document.addEventListener('pointerdown', handleDocClickForMenu)
window.addEventListener('archipelago:share-to-mesh', loadPendingFromSession)
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', updateKeyboardInset)
@@ -403,7 +403,7 @@ onMounted(async () => {
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
- document.removeEventListener('click', handleDocClickForMenu)
+ document.removeEventListener('pointerdown', handleDocClickForMenu)
window.removeEventListener('archipelago:share-to-mesh', loadPendingFromSession)
if (window.visualViewport) {
window.visualViewport.removeEventListener('resize', updateKeyboardInset)
@@ -1337,8 +1337,8 @@ function closeAttachMenuOnOutsideClick(ev: MouseEvent) {
const target = ev.target as HTMLElement
if (!target.closest('.mesh-attach-menu-anchor')) showAttachMenu.value = false
}
-onMounted(() => document.addEventListener('click', closeAttachMenuOnOutsideClick))
-onUnmounted(() => document.removeEventListener('click', closeAttachMenuOnOutsideClick))
+onMounted(() => document.addEventListener('pointerdown', closeAttachMenuOnOutsideClick))
+onUnmounted(() => document.removeEventListener('pointerdown', closeAttachMenuOnOutsideClick))
const attachError = ref(null)
const fetchingCids = ref>(new Set())
const fetchedUrls = ref