diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a2fb70c..006adc3 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -182,15 +182,31 @@ } }); - // Apply font size setting as CSS variable (legacy — kept for backwards compat) + // Apply font size setting as CSS variable (legacy, kept for backwards compat). + // Scoped to rather than documentElement so the write only invalidates + // styles on the body subtree (transcript surfaces inherit from body anyway). $effect(() => { - document.documentElement.style.setProperty("--font-size-transcript", `${settings.fontSize}px`); + document.body.style.setProperty("--font-size-transcript", `${settings.fontSize}px`); }); - // Check whether the keydown originates from a text input (avoid triggering while typing) + // Custom widgets that should swallow single-letter shortcuts so they don't + // accidentally trigger global hotkeys while focused. + const CUSTOM_WIDGET_SELECTOR = + '[role="combobox"], [role="listbox"], [role="radio"], [role="switch"], [role="menuitem"], [role="tab"]'; + + // Check whether the keydown originates from a text input or custom widget + // (avoid triggering shortcuts while typing or while focus sits in a + // SegmentedButton, ZonePicker, or similar ARIA-roled control). function isInputFocused(e) { const tag = e.target?.tagName; - return tag === "INPUT" || tag === "TEXTAREA" || e.target?.isContentEditable; + if (tag === "INPUT" || tag === "TEXTAREA" || e.target?.isContentEditable) { + return true; + } + const active = document.activeElement; + if (active && typeof active.closest === "function" && active.closest(CUSTOM_WIDGET_SELECTOR)) { + return true; + } + return false; } function handleKeydown(e) {