From 7c8c804dacd1747101c0949a3ca26c94c690af79 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Wed, 20 May 2026 02:35:59 +0800
Subject: [PATCH] Release TagLauncher 7.5.1

---
 Apptag/ApptagApp.swift            |  258 +++
 Apptag/Localization/cs.json       |   41 
 Apptag/Localization/no.json       |   41 
 Apptag/Localization/zh-Hant.json  |   41 
 Apptag/Localization/ja.json       |   41 
 Apptag/Info.plist                 |    4 
 Apptag/Localization/th.json       |   41 
 Apptag/Localization/nl.json       |   41 
 Apptag/Localization/sr-Cyrl.json  |   41 
 Apptag/Localization/zh-Hans.json  |   41 
 Apptag/Localization/de.json       |   41 
 Apptag/Localization/ms.json       |   41 
 Apptag/Localization/nn.json       |   41 
 Apptag/Localization/pt-BR.json    |   41 
 Apptag/Localization/es.json       |   41 
 Apptag/Localization/tr.json       |   41 
 Apptag/Localization/en.json       |   41 
 Apptag/Localization/nb.json       |   41 
 Apptag/Localization/ar.json       |   41 
 Apptag/PreferencesView.swift      |  602 +++++++--
 Apptag/Localization/vi.json       |   41 
 Apptag/Localization/fr.json       |   41 
 Apptag/Localization/id.json       |   41 
 Apptag/Localization/da.json       |   41 
 CHANGELOG.md                      |   19 
 Apptag/Localization/uk.json       |   41 
 Apptag/QuickSearch.swift          | 1080 ++++++++++++++++++
 Apptag/Localization/ar-Najdi.json |   41 
 Apptag/Localization/ko.json       |   41 
 Apptag/ContentView.swift          |  317 ++++
 Apptag/DataLayer.swift            |   22 
 Apptag/Localization/it.json       |   41 
 Apptag/Localization/sv.json       |   41 
 Apptag/Localization/ro.json       |   41 
 Apptag/AppDefaults.swift          |   24 
 Apptag/Localization/pl.json       |   41 
 Apptag/Localization/ru.json       |   41 
 37 files changed, 3,285 insertions(+), 230 deletions(-)

diff --git a/Apptag/AppDefaults.swift b/Apptag/AppDefaults.swift
index 973798e..2f2f720 100644
--- a/Apptag/AppDefaults.swift
+++ b/Apptag/AppDefaults.swift
@@ -2,7 +2,7 @@
 
 enum AppDefaults {
     static let schemaVersionKey = "initialDefaultsSchemaVersion"
-    static let currentSchemaVersion = 1
+    static let currentSchemaVersion = 2
 
     static let tagFontSize: Double = 22
     static let iconSize: Double = 80
@@ -24,10 +24,32 @@
             "launchAtLogin": launchAtLogin,
             "showUncommonAppBubbles": showUncommonAppBubbles
         ])
+        migrateShortcutDefaultsIfNeeded()
     }
 
     static func hasStoredValue(for key: String) -> Bool {
         let domain = Bundle.main.bundleIdentifier ?? "com.apptag.launcher"
         return UserDefaults.standard.persistentDomain(forName: domain)?[key] != nil
     }
+
+    private static func migrateShortcutDefaultsIfNeeded() {
+        let defaults = UserDefaults.standard
+        guard defaults.integer(forKey: schemaVersionKey) < currentSchemaVersion else { return }
+
+        defaults.set(LauncherHotkey.defaultMain.serialized, forKey: LauncherHotkeyKind.main.storageKey)
+        defaults.removeObject(forKey: LauncherHotkeyKind.main.pendingStorageKey)
+        defaults.removeObject(forKey: LauncherHotkeyKind.main.statusKey)
+        defaults.removeObject(forKey: LauncherHotkeyKind.main.conflictMessageKey)
+
+        let quickSearchKey = LauncherHotkeyKind.quickSearch.storageKey
+        let storedQuickSearch = defaults.string(forKey: quickSearchKey) ?? ""
+        if storedQuickSearch.isEmpty {
+            defaults.set(LauncherHotkey.defaultQuickSearch.serialized, forKey: quickSearchKey)
+            defaults.removeObject(forKey: LauncherHotkeyKind.quickSearch.pendingStorageKey)
+            defaults.removeObject(forKey: LauncherHotkeyKind.quickSearch.statusKey)
+            defaults.removeObject(forKey: LauncherHotkeyKind.quickSearch.conflictMessageKey)
+        }
+
+        defaults.set(currentSchemaVersion, forKey: schemaVersionKey)
+    }
 }
diff --git a/Apptag/ApptagApp.swift b/Apptag/ApptagApp.swift
index 72a1665..cd12e0b 100644
--- a/Apptag/ApptagApp.swift
+++ b/Apptag/ApptagApp.swift
@@ -33,7 +33,6 @@
     private static let statusItemButtonIdentifier = NSUserInterfaceItemIdentifier("TagLauncherStatusItemButton")
     private static let statusItemAccessibilityLabel = "TagLauncher"
     private static let showAppListMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherShowAppListMenuItem")
-    private static let showAppListShortcutGlyphs = "⌥⇧␣"
     private static let overlayDefaultLevel = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
     private static let overlayTextInputLevel = NSWindow.Level.modalPanel
 
@@ -41,7 +40,12 @@
     private var overlayWindow: NSWindow?
     private var overlayKeyMonitor: Any?
     private var settingsWindow: NSWindow?    // Track Settings window to keep it above overlay
-    private var hotkeyRef: EventHotKeyRef?
+    private var mainHotkeyRef: EventHotKeyRef?
+    private var quickSearchHotkeyRef: EventHotKeyRef?
+    private var hotkeyEventHandlerInstalled = false
+    private var isQuickSearchOpen = false
+    private var isModalInteractionActive = false
+    private var areHotkeysPausedForCapture = false
     private var isInEditMode = false  // Suppress auto-dismiss during editing
     private var isEditingAppNote = false
     private var isConfiguringApplicationMenu = false
@@ -61,11 +65,12 @@
         migrateDefaultGroupName()
         TagDatabase.seedDefaultTags()
         syncChromeSettings(force: true)
-        registerHotkey()
+        registerConfiguredHotkeys()
         observeOtherWindows()
         observeSettingsClose()
         observeEditMode()
         observeAppNoteEditing()
+        observeQuickSearch()
         observePreferencesRequests()
         observeApplicationMenuChanges()
         observeChromeSettings()
@@ -333,7 +338,10 @@
     }
 
     private var showAppListMenuTitle: String {
-        "\(tr("menu.showAppList"))  \(Self.showAppListShortcutGlyphs)"
+        if let hotkey = LauncherHotkeyStore.hotkey(for: .main) {
+            return "\(tr("menu.showAppList"))  \(hotkey.displayString)"
+        }
+        return tr("menu.showAppList")
     }
 
     private func observeApplicationMenuChanges() {
@@ -502,7 +510,7 @@
         }
     }
 
-    private func showOverlay() {
+    private func showOverlay(initialQuickSearchSource: String? = nil) {
         // Use the screen under the mouse cursor — works in fullscreen spaces
         let mousePoint = NSEvent.mouseLocation
         guard let screen = NSScreen.screens.first(where: {
@@ -513,7 +521,7 @@
         if let existingWindow = overlayWindow {
             window = existingWindow
         } else {
-            window = makeOverlayWindow(on: screen)
+            window = makeOverlayWindow(on: screen, initialQuickSearchSource: initialQuickSearchSource)
             overlayWindow = window
         }
 
@@ -521,6 +529,14 @@
         window.level = isEditingAppNote ? Self.overlayTextInputLevel : Self.overlayDefaultLevel
 
         installOverlayKeyMonitor()
+
+        if let initialQuickSearchSource {
+            NotificationCenter.default.post(
+                name: .tagLauncherQuickSearchRequested,
+                object: nil,
+                userInfo: ["source": initialQuickSearchSource]
+            )
+        }
 
         window.makeKeyAndOrderFront(nil)
         window.orderFrontRegardless()
@@ -530,12 +546,58 @@
     private func installOverlayKeyMonitor() {
         guard overlayKeyMonitor == nil else { return }
         overlayKeyMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
+            guard let self else { return event }
             if event.keyCode == 53 { // Escape
-                self?.hideOverlay()
+                if self.isQuickSearchOpen {
+                    NotificationCenter.default.post(name: .tagLauncherQuickSearchDismissRequested, object: nil)
+                    return nil
+                }
+                self.hideOverlay()
+                return nil
+            }
+            if self.shouldOpenQuickSearch(for: event) {
+                NotificationCenter.default.post(
+                    name: .tagLauncherQuickSearchRequested,
+                    object: nil,
+                    userInfo: ["source": QuickSearchOpenSource.mainOverlay]
+                )
                 return nil
             }
             return event
         }
+    }
+
+    private func shouldOpenQuickSearch(for event: NSEvent) -> Bool {
+        guard event.keyCode == UInt16(kVK_Space),
+              !event.isARepeat,
+              event.modifierFlags.intersection(.deviceIndependentFlagsMask).isEmpty,
+              overlayWindow?.isVisible == true,
+              !isQuickSearchOpen,
+              !isInEditMode,
+              !isEditingAppNote,
+              !isModalInteractionActive
+        else { return false }
+
+        guard let firstResponder = overlayWindow?.firstResponder else { return true }
+        if firstResponder is NSText || firstResponder is NSTextField {
+            return false
+        }
+        if let responderView = firstResponder as? NSView,
+           viewOrAncestorHandlesSpace(responderView) {
+            return false
+        }
+        return true
+    }
+
+    private func viewOrAncestorHandlesSpace(_ view: NSView) -> Bool {
+        var current: NSView? = view
+        while let candidate = current {
+            if candidate is NSButton || candidate is NSSegmentedControl || candidate is NSSlider {
+                return true
+            }
+            current = candidate.superview
+        }
+        return false
     }
 
     private func removeOverlayKeyMonitor() {
@@ -545,7 +607,7 @@
         }
     }
 
-    private func makeOverlayWindow(on screen: NSScreen) -> NSWindow {
+    private func makeOverlayWindow(on screen: NSScreen, initialQuickSearchSource: String? = nil) -> NSWindow {
         let panel = OverlayPanel(
             contentRect: screen.frame,
             styleMask: [.borderless, .fullSizeContentView, .nonactivatingPanel],
@@ -568,9 +630,12 @@
         panel.titleVisibility = .hidden
         panel.isReleasedWhenClosed = false
         panel.contentView = DismissibleHostingView(
-            rootView: ContentView(hideOverlay: { [weak self] in
-                self?.hideOverlay(force: true)
-            }),
+            rootView: ContentView(
+                hideOverlay: { [weak self] in
+                    self?.hideOverlay(force: true)
+                },
+                initialQuickSearchSource: initialQuickSearchSource
+            ),
             onBackdropTap: { [weak self] in
                 self?.hideOverlay()
             }
@@ -592,48 +657,106 @@
         }
     }
 
-    // MARK: - Global Hotkey (Shift+Option+Space)
+    // MARK: - Global Hotkeys
 
-    /// Carbon RegisterEventHotKey. If it fails (sandbox, etc.), falls back to menu bar only.
-    private func registerHotkey() {
+    private func registerConfiguredHotkeys() {
+        installHotkeyEventHandlerIfNeeded()
+        registerStoredHotkey(.main)
+        registerStoredHotkey(.quickSearch)
+    }
+
+    @discardableResult
+    func applyHotkey(_ hotkey: LauncherHotkey?, for kind: LauncherHotkeyKind) -> Bool {
+        installHotkeyEventHandlerIfNeeded()
+
+        if hotkey == nil {
+            unregisterHotkey(for: kind)
+            LauncherHotkeyStore.save(nil, for: kind)
+            LauncherHotkeyStore.setStatus(.disabled, message: nil, for: kind)
+            return true
+        }
+
+        guard let hotkey else { return false }
+        let previousRef = hotkeyRef(for: kind)
+        if previousRef != nil, LauncherHotkeyStore.hotkey(for: kind) == hotkey {
+            LauncherHotkeyStore.setStatus(.active, message: nil, for: kind)
+            return true
+        }
+        setHotkeyRef(nil, for: kind)
+
         var hotkeyID = EventHotKeyID()
         hotkeyID.signature = OSType(0x41505447) // 'APTG'
-        hotkeyID.id = 1
+        hotkeyID.id = kind.eventID
 
-        let modifiers = UInt32(shiftKey | optionKey)
-
-        var ref: EventHotKeyRef?
+        var newRef: EventHotKeyRef?
         let status = RegisterEventHotKey(
-            UInt32(kVK_Space),
-            modifiers,
+            hotkey.keyCode,
+            hotkey.modifiers,
             hotkeyID,
             GetApplicationEventTarget(),
             0,
-            &ref
+            &newRef
         )
-        hotkeyRef = ref
 
-        if status != noErr {
-            print("[TagLauncher] Hotkey registration failed: \(status). Falling back to menu bar only.")
-            return
+        if status == noErr, let newRef {
+            if let previousRef { UnregisterEventHotKey(previousRef) }
+            setHotkeyRef(newRef, for: kind)
+            LauncherHotkeyStore.save(hotkey, for: kind)
+            LauncherHotkeyStore.setStatus(.active, message: nil, for: kind)
+            return true
         }
+
+        setHotkeyRef(previousRef, for: kind)
+        let message = LauncherHotkeyStore.knownConflictMessage(for: hotkey, status: status)
+            ?? tr("quickSearch.hotkeyConflict.generic")
+        LauncherHotkeyStore.savePending(hotkey, for: kind)
+        LauncherHotkeyStore.setStatus(.conflict, message: message, for: kind)
+        print("[TagLauncher] Hotkey registration failed for \(kind.rawValue): \(status)")
+        return false
+    }
+
+    func retryHotkeyRegistration(for kind: LauncherHotkeyKind) {
+        _ = applyHotkey(
+            LauncherHotkeyStore.pendingHotkey(for: kind) ?? LauncherHotkeyStore.hotkey(for: kind),
+            for: kind
+        )
+    }
+
+    private func registerStoredHotkey(_ kind: LauncherHotkeyKind) {
+        _ = applyHotkey(LauncherHotkeyStore.hotkey(for: kind), for: kind)
+    }
+
+    private func installHotkeyEventHandlerIfNeeded() {
+        guard !hotkeyEventHandlerInstalled else { return }
+        hotkeyEventHandlerInstalled = true
 
         var eventSpec = EventTypeSpec(
             eventClass: OSType(kEventClassKeyboard),
             eventKind: UInt32(kEventHotKeyPressed)
         )
-
         let selfPtr = Unmanaged.passUnretained(self).toOpaque()
 
         InstallEventHandler(
             GetApplicationEventTarget(),
-            { (_, _, userData) -> OSStatus in
-                guard let userData else { return noErr }
+            { (_, event, userData) -> OSStatus in
+                guard let event, let userData else { return noErr }
+                var hotkeyID = EventHotKeyID()
+                let status = GetEventParameter(
+                    event,
+                    EventParamName(kEventParamDirectObject),
+                    EventParamType(typeEventHotKeyID),
+                    nil,
+                    MemoryLayout<EventHotKeyID>.size,
+                    nil,
+                    &hotkeyID
+                )
+                guard status == noErr else { return noErr }
+
                 let delegate = Unmanaged<AppDelegate>
                     .fromOpaque(userData)
                     .takeUnretainedValue()
                 DispatchQueue.main.async {
-                    delegate.toggleOverlay()
+                    delegate.handleHotkeyEvent(id: hotkeyID.id)
                 }
                 return noErr
             },
@@ -642,6 +765,40 @@
             selfPtr,
             nil
         )
+    }
+
+    private func handleHotkeyEvent(id: UInt32) {
+        if id == LauncherHotkeyKind.quickSearch.eventID {
+            showQuickSearchFromGlobalHotkey()
+        } else {
+            toggleOverlay()
+        }
+    }
+
+    private func showQuickSearchFromGlobalHotkey() {
+        guard overlayWindow?.isVisible != true else { return }
+        showOverlay(initialQuickSearchSource: QuickSearchOpenSource.globalHidden)
+    }
+
+    private func hotkeyRef(for kind: LauncherHotkeyKind) -> EventHotKeyRef? {
+        switch kind {
+        case .main: return mainHotkeyRef
+        case .quickSearch: return quickSearchHotkeyRef
+        }
+    }
+
+    private func setHotkeyRef(_ ref: EventHotKeyRef?, for kind: LauncherHotkeyKind) {
+        switch kind {
+        case .main: mainHotkeyRef = ref
+        case .quickSearch: quickSearchHotkeyRef = ref
+        }
+    }
+
+    private func unregisterHotkey(for kind: LauncherHotkeyKind) {
+        if let ref = hotkeyRef(for: kind) {
+            UnregisterEventHotKey(ref)
+            setHotkeyRef(nil, for: kind)
+        }
     }
 
     // MARK: - Preferences
@@ -780,6 +937,38 @@
         }
     }
 
+    private func observeQuickSearch() {
+        NotificationCenter.default.addObserver(
+            forName: .tagLauncherQuickSearchVisibilityChanged,
+            object: nil,
+            queue: .main
+        ) { [weak self] notification in
+            self?.isQuickSearchOpen = (notification.userInfo?["active"] as? Bool) ?? false
+        }
+
+        NotificationCenter.default.addObserver(
+            forName: .tagLauncherModalInteractionChanged,
+            object: nil,
+            queue: .main
+        ) { [weak self] notification in
+            guard let self else { return }
+            let active = (notification.userInfo?["active"] as? Bool) ?? false
+            self.isModalInteractionActive = active
+            if (notification.userInfo?["source"] as? String) == "hotkeyRecording" {
+                self.setHotkeysPausedForCapture(active)
+            }
+        }
+
+        NotificationCenter.default.addObserver(
+            forName: .tagLauncherHotkeysChanged,
+            object: nil,
+            queue: .main
+        ) { [weak self] _ in
+            self?.setupMenuBar()
+            self?.configureApplicationMenuWhenAvailable(retries: 2)
+        }
+    }
+
     private func updateOverlayLevelForTextInput() {
         guard let overlayWindow else { return }
         overlayWindow.level = isEditingAppNote ? Self.overlayTextInputLevel : Self.overlayDefaultLevel
@@ -788,6 +977,17 @@
         }
     }
 
+    private func setHotkeysPausedForCapture(_ paused: Bool) {
+        guard areHotkeysPausedForCapture != paused else { return }
+        areHotkeysPausedForCapture = paused
+        if paused {
+            unregisterHotkey(for: .main)
+            unregisterHotkey(for: .quickSearch)
+        } else {
+            registerConfiguredHotkeys()
+        }
+    }
+
     /// The overlay buttons live inside SwiftUI; use an app-level notification like edit mode does.
     private func observePreferencesRequests() {
         NotificationCenter.default.addObserver(
diff --git a/Apptag/ContentView.swift b/Apptag/ContentView.swift
index b9bb245..8e1cf0e 100644
--- a/Apptag/ContentView.swift
+++ b/Apptag/ContentView.swift
@@ -337,6 +337,7 @@
 
 struct ContentView: View {
     let hideOverlay: () -> Void
+    private let initialQuickSearchSource: String?
 
     @State private var allApps: [AppInfo] = []
     @State private var tagColors: [String: Int] = [:]
@@ -377,6 +378,27 @@
     @State private var bubbleDraftNote = ""
     @FocusState private var bubbleNoteFocused: Bool
 
+    // Quick Search
+    @State private var quickSearchVisible = false
+    @State private var quickSearchQuery = ""
+    @State private var quickSearchDocuments: [QuickSearchDocument] = []
+    @State private var quickSearchResults: [QuickSearchResult] = []
+    @State private var quickSearchSelectedID: URL? = nil
+    @State private var quickSearchManualSelection = false
+    @State private var quickSearchFocusToken = 0
+    @State private var quickSearchCloseHidesOverlay = false
+    @State private var quickSearchErrorMessage: String? = nil
+    @State private var initialQuickSearchConsumed = false
+
+    init(hideOverlay: @escaping () -> Void, initialQuickSearchSource: String? = nil) {
+        self.hideOverlay = hideOverlay
+        self.initialQuickSearchSource = initialQuickSearchSource
+        let startsInQuickSearch = initialQuickSearchSource != nil
+        _quickSearchVisible = State(initialValue: startsInQuickSearch)
+        _quickSearchCloseHidesOverlay = State(initialValue: initialQuickSearchSource == QuickSearchOpenSource.globalHidden)
+        _quickSearchFocusToken = State(initialValue: startsInQuickSearch ? 1 : 0)
+    }
+
     // Configurable defaults
     @AppStorage("defaultGroupName") private var defaultGroupName = "Other"
     @AppStorage("tagFontSize") private var tagFontSize: Double = AppDefaults.tagFontSize
@@ -411,37 +433,47 @@
         displayMode == "coloredContainer" || displayMode == "coloredGridContainer"
     }
 
+    private var quickSearchOnlyMode: Bool {
+        quickSearchVisible && quickSearchCloseHidesOverlay
+    }
+
     var body: some View {
         ZStack {
-            VisualEffectView(material: .hudWindow, blendingMode: .behindWindow)
-                .ignoresSafeArea()
-                .allowsHitTesting(false)
+            if !quickSearchOnlyMode {
+                VisualEffectView(material: .hudWindow, blendingMode: .behindWindow)
+                    .ignoresSafeArea()
+                    .allowsHitTesting(false)
+            }
 
-            if notchHeight > 0 {
-                VStack {
-                    Rectangle().fill(.black)
-                        .frame(height: notchHeight)
-                        .ignoresSafeArea(edges: .top)
-                    Spacer()
+            if !quickSearchOnlyMode {
+                if notchHeight > 0 {
+                    VStack {
+                        Rectangle().fill(.black)
+                            .frame(height: notchHeight)
+                            .ignoresSafeArea(edges: .top)
+                        Spacer()
+                    }
+                    .allowsHitTesting(false)
                 }
-                .allowsHitTesting(false)
+
+                switch editPhase {
+                case .none:
+                    normalContent
+                case .editingTags:
+                    editTagsView
+                case .editingApps:
+                    editAppsView
+                }
+
+                uncommonAppBubbleOverlay
+                smartStartNoticeOverlay
+                editActionFeedbackOverlay
+                uncategorizedDropConfirmOverlay
             }
 
-            switch editPhase {
-            case .none:
-                normalContent
-            case .editingTags:
-                editTagsView
-            case .editingApps:
-                editAppsView
-            }
+            quickSearchOverlay
 
-            uncommonAppBubbleOverlay
-            smartStartNoticeOverlay
-            editActionFeedbackOverlay
-            uncategorizedDropConfirmOverlay
-
-            if let message = dropWarningToast {
+            if !quickSearchOnlyMode, let message = dropWarningToast {
                 Text(message)
                     .font(.system(size: 16, weight: .semibold))
                     .foregroundStyle(.primary)
@@ -456,7 +488,7 @@
                     .allowsHitTesting(false)
             }
 
-            if dropRefreshVisible {
+            if !quickSearchOnlyMode && dropRefreshVisible {
                 Color.black.opacity(0.08)
                     .ignoresSafeArea()
                     .transition(.opacity)
@@ -479,6 +511,17 @@
         .onAppear {
             refreshNotchHeight()
             refreshApps()
+            if let initialQuickSearchSource, !initialQuickSearchConsumed {
+                initialQuickSearchConsumed = true
+                quickSearchCloseHidesOverlay = initialQuickSearchSource == QuickSearchOpenSource.globalHidden
+                quickSearchVisible = true
+                quickSearchFocusToken &+= 1
+                NotificationCenter.default.post(
+                    name: .tagLauncherQuickSearchVisibilityChanged,
+                    object: nil,
+                    userInfo: ["active": true]
+                )
+            }
         }
         .onReceive(NotificationCenter.default.publisher(for: .tagLauncherOverlayDidShow)) { _ in
             resetTransientDragState()
@@ -487,6 +530,14 @@
         }
         .onReceive(NotificationCenter.default.publisher(for: .tagLauncherOverlayDidHide)) { _ in
             resetTransientDragState()
+            closeQuickSearch(notify: true, hideOverlayIfNeeded: false)
+        }
+        .onReceive(NotificationCenter.default.publisher(for: .tagLauncherQuickSearchRequested)) { notification in
+            let source = notification.userInfo?["source"] as? String ?? QuickSearchOpenSource.mainOverlay
+            openQuickSearch(source: source)
+        }
+        .onReceive(NotificationCenter.default.publisher(for: .tagLauncherQuickSearchDismissRequested)) { _ in
+            closeQuickSearch()
         }
         .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
             guard allApps.isEmpty, !refreshInProgress else { return }
@@ -517,6 +568,10 @@
             if editingBubble != nil && !focused {
                 commitBubbleNote()
             }
+        }
+        .onChange(of: quickSearchQuery) { _, _ in
+            quickSearchErrorMessage = nil
+            refreshQuickSearchResults()
         }
         .onChange(of: pendingUncategorizedDrop != nil) { _, active in
             NotificationCenter.default.post(
@@ -551,6 +606,179 @@
                 NotificationCenter.default.post(name: .tagLauncherEditModeChanged, object: nil, userInfo: ["active": false])
             }
         }
+    }
+
+    // MARK: - Quick Search
+
+    private var quickSearchOverlay: some View {
+        GeometryReader { proxy in
+            if quickSearchVisible {
+                QuickSearchBackdropClickView {
+                    closeQuickSearch()
+                }
+                    .frame(width: proxy.size.width, height: proxy.size.height)
+                    .ignoresSafeArea()
+                    .zIndex(899)
+
+                QuickSearchOverlayView(
+                    query: $quickSearchQuery,
+                    results: quickSearchResults,
+                    selectedID: quickSearchSelectedID,
+                    focusToken: quickSearchFocusToken,
+                    isLoading: quickSearchDocuments.isEmpty && refreshInProgress,
+                    maxVisibleRows: quickSearchMaxVisibleRows(in: proxy.size),
+                    errorMessage: quickSearchErrorMessage,
+                    onCommand: handleQuickSearchCommand,
+                    onHover: selectQuickSearchResult,
+                    onLaunch: launchQuickSearchResult
+                )
+                .position(
+                    x: proxy.size.width / 2,
+                    y: quickSearchPanelCenterY(in: proxy.size)
+                )
+                .transition(.scale(scale: 0.98).combined(with: .opacity))
+                .zIndex(900)
+            }
+        }
+        .ignoresSafeArea()
+        .animation(.easeOut(duration: 0.12), value: quickSearchVisible)
+    }
+
+    private func quickSearchPanelCenterY(in size: CGSize) -> CGFloat {
+        let visibleRows = max(1, min(quickSearchResults.isEmpty ? 1 : quickSearchResults.count, quickSearchMaxVisibleRows(in: size)))
+        let estimatedPanelHeight = CGFloat(visibleRows) * 76 + 122
+        return quickSearchPanelTopY(in: size) + estimatedPanelHeight / 2
+    }
+
+    private func quickSearchPanelTopY(in size: CGSize) -> CGFloat {
+        max(notchHeight + 54, min(112, size.height * 0.12))
+    }
+
+    private func quickSearchMaxVisibleRows(in size: CGSize) -> Int {
+        let bottomClearance: CGFloat = 84
+        let chromeHeight: CGFloat = 122
+        let rowHeightWithSpacing: CGFloat = 76
+        let availableHeight = max(0, size.height - quickSearchPanelTopY(in: size) - bottomClearance - chromeHeight)
+        return max(1, min(8, Int(floor(availableHeight / rowHeightWithSpacing))))
+    }
+
+    private func openQuickSearch(source: String) {
+        guard canOpenQuickSearch else { return }
+        dismissAppBubble()
+        quickSearchCloseHidesOverlay = source == QuickSearchOpenSource.globalHidden
+        quickSearchVisible = true
+        quickSearchQuery = ""
+        quickSearchManualSelection = false
+        quickSearchErrorMessage = nil
+        quickSearchFocusToken &+= 1
+        refreshQuickSearchResults()
+        NotificationCenter.default.post(
+            name: .tagLauncherQuickSearchVisibilityChanged,
+            object: nil,
+            userInfo: ["active": true]
+        )
+    }
+
+    private var canOpenQuickSearch: Bool {
+        editPhase == .none
+            && pendingUncategorizedDrop == nil
+            && smartStartNotice == nil
+            && !dropRefreshVisible
+            && !quickSearchVisible
+    }
+
+    private func closeQuickSearch(notify: Bool = true, hideOverlayIfNeeded: Bool = true) {
+        let shouldHideOverlay = quickSearchVisible && quickSearchCloseHidesOverlay && hideOverlayIfNeeded
+        guard quickSearchVisible else { return }
+        quickSearchVisible = false
+        quickSearchQuery = ""
+        quickSearchResults = []
+        quickSearchSelectedID = nil
+        quickSearchManualSelection = false
+        quickSearchErrorMessage = nil
+        quickSearchCloseHidesOverlay = false
+        if notify {
+            NotificationCenter.default.post(
+                name: .tagLauncherQuickSearchVisibilityChanged,
+                object: nil,
+                userInfo: ["active": false]
+            )
+        }
+        if shouldHideOverlay {
+            hideOverlay()
+        }
+    }
+
+    private func refreshQuickSearchResults() {
+        let previousSelection = quickSearchSelectedID
+        quickSearchResults = QuickSearchEngine.search(quickSearchQuery, documents: quickSearchDocuments)
+
+        if quickSearchResults.isEmpty {
+            quickSearchSelectedID = nil
+            quickSearchManualSelection = false
+            return
+        }
+
+        if quickSearchManualSelection,
+           let previousSelection,
+           quickSearchResults.contains(where: { $0.id == previousSelection }) {
+            quickSearchSelectedID = previousSelection
+        } else {
+            quickSearchSelectedID = quickSearchResults.first?.id
+            quickSearchManualSelection = false
+        }
+    }
+
+    private func handleQuickSearchCommand(_ command: QuickSearchCommand) {
+        switch command {
+        case .moveUp:
+            moveQuickSearchSelection(by: -1)
+        case .moveDown:
+            moveQuickSearchSelection(by: 1)
+        case .submit:
+            guard let selected = selectedQuickSearchResult else { return }
+            launchQuickSearchResult(selected)
+        case .dismiss:
+            closeQuickSearch()
+        }
+    }
+
+    private var selectedQuickSearchResult: QuickSearchResult? {
+        guard let quickSearchSelectedID else { return nil }
+        return quickSearchResults.first { $0.id == quickSearchSelectedID }
+    }
+
+    private func moveQuickSearchSelection(by delta: Int) {
+        guard !quickSearchResults.isEmpty else { return }
+        let currentIndex = quickSearchSelectedID.flatMap { id in
+            quickSearchResults.firstIndex { $0.id == id }
+        } ?? 0
+        let nextIndex = min(max(currentIndex + delta, 0), quickSearchResults.count - 1)
+        quickSearchSelectedID = quickSearchResults[nextIndex].id
+        quickSearchManualSelection = true
+    }
+
+    private func selectQuickSearchResult(_ result: QuickSearchResult) {
+        quickSearchSelectedID = result.id
+        quickSearchManualSelection = true
+    }
+
+    private func launchQuickSearchResult(_ result: QuickSearchResult) {
+        quickSearchErrorMessage = nil
+        launchApp(
+            result.app,
+            closeQuickSearchOnSuccess: true,
+            closeOverlayOnSuccess: true,
+            onFailure: {
+                quickSearchErrorMessage = tr("quickSearch.launchFailed")
+                quickSearchFocusToken &+= 1
+                NSAccessibility.post(
+                    element: NSApp.mainWindow as Any,
+                    notification: .announcementRequested,
+                    userInfo: [.announcement: tr("quickSearch.launchFailed")]
+                )
+            }
+        )
     }
 
     // MARK: - Normal Content
@@ -2304,12 +2532,17 @@
             )
             let store = smartStartResult.store
             let apps = TagEditor.annotate(apps: scannedApps, store: store)
+            let quickSearchDocs = QuickSearchEngine.makeDocuments(apps: apps, store: store)
             let colors = store.tags.mapValues { $0.color }
             let order = TagEditor.orderedTagNames()
             DispatchQueue.main.async {
                 allApps = apps
+                quickSearchDocuments = quickSearchDocs
                 tagColors = colors
                 draggedTagNames = order
+                if quickSearchVisible {
+                    refreshQuickSearchResults()
+                }
                 handleSmartStartRunResult(smartStartResult)
                 if forceLayoutRefresh {
                     finishDropRefreshAfterMinimumDuration()
@@ -2325,15 +2558,37 @@
         }
     }
 
-    func openApp(_ app: AppInfo) {
+    private func launchApp(
+        _ app: AppInfo,
+        closeQuickSearchOnSuccess: Bool = false,
+        closeOverlayOnSuccess: Bool = true,
+        onFailure: (() -> Void)? = nil
+    ) {
         appDragModeActive = false
         endTagNavReorder()
-        hideOverlay()
-        DispatchQueue.global(qos: .utility).async {
-            TagEditor.recordLauncherOpen(for: app.path.path)
-        }
         let configuration = NSWorkspace.OpenConfiguration()
-        NSWorkspace.shared.openApplication(at: app.path, configuration: configuration)
+        NSWorkspace.shared.openApplication(at: app.path, configuration: configuration) { _, error in
+            DispatchQueue.main.async {
+                guard error == nil else {
+                    onFailure?()
+                    return
+                }
+
+                DispatchQueue.global(qos: .utility).async {
+                    TagEditor.recordLauncherOpen(for: app.path.path)
+                }
+                if closeQuickSearchOnSuccess {
+                    closeQuickSearch(hideOverlayIfNeeded: false)
+                }
+                if closeOverlayOnSuccess {
+                    hideOverlay()
+                }
+            }
+        }
+    }
+
+    func openApp(_ app: AppInfo) {
+        launchApp(app)
     }
 }
 
diff --git a/Apptag/DataLayer.swift b/Apptag/DataLayer.swift
index 779beac..59371d9 100644
--- a/Apptag/DataLayer.swift
+++ b/Apptag/DataLayer.swift
@@ -339,6 +339,7 @@
         var uncommonAppPaths: [String] = []  // special marker; does not affect normal groups
         var uncommonSources: [String: UncommonSource] = [:]  // current uncommon source: auto/manual
         var appOpenCounts: [String: Int] = [:]  // launches opened from TagLauncher
+        var appLastOpenedAt: [String: Date] = [:]  // successful launches opened from TagLauncher
         var knownAppPaths: [String] = []  // baseline set to detect newly installed apps
         var appNotes: [String: String] = [:]  // path → user note; retained even if marker is removed
         var disabledSystemCategoryIDs: [SmartCategoryID] = []  // system categories the user deleted
@@ -353,6 +354,7 @@
             case uncommonAppPaths
             case uncommonSources
             case appOpenCounts
+            case appLastOpenedAt
             case knownAppPaths
             case appNotes
             case disabledSystemCategoryIDs
@@ -371,6 +373,7 @@
             uncommonAppPaths = try container.decodeIfPresent([String].self, forKey: .uncommonAppPaths) ?? []
             uncommonSources = try container.decodeIfPresent([String: UncommonSource].self, forKey: .uncommonSources) ?? [:]
             appOpenCounts = try container.decodeIfPresent([String: Int].self, forKey: .appOpenCounts) ?? [:]
+            appLastOpenedAt = try container.decodeIfPresent([String: Date].self, forKey: .appLastOpenedAt) ?? [:]
             knownAppPaths = try container.decodeIfPresent([String].self, forKey: .knownAppPaths) ?? []
             appNotes = try container.decodeIfPresent([String: String].self, forKey: .appNotes) ?? [:]
             disabledSystemCategoryIDs = try container.decodeIfPresent(
@@ -1181,7 +1184,21 @@
         }
 
         let newPaths = scannedPaths.subtracting(knownPaths)
-        guard !newPaths.isEmpty else { return store }
+        let removedPaths = knownPaths.subtracting(scannedPaths)
+        if !removedPaths.isEmpty {
+            for path in removedPaths {
+                store.appOpenCounts.removeValue(forKey: path)
+                store.appLastOpenedAt.removeValue(forKey: path)
+            }
+            store.knownAppPaths = knownPaths.subtracting(removedPaths).sorted()
+        }
+
+        guard !newPaths.isEmpty else {
+            if !removedPaths.isEmpty {
+                TagDatabase.save(store)
+            }
+            return store
+        }
 
         var uncommonPaths = Set(store.uncommonAppPaths)
         let appsByPath = Dictionary(uniqueKeysWithValues: apps.map { ($0.path.path, $0) })
@@ -1201,7 +1218,7 @@
         let newApps = apps.filter { newPaths.contains($0.path.path) }
         _ = seedDefaultAppleAppNotes(for: newApps, in: &store)
         store.uncommonAppPaths = uncommonPaths.sorted()
-        store.knownAppPaths = knownPaths.union(newPaths).sorted()
+        store.knownAppPaths = Set(store.knownAppPaths).union(newPaths).sorted()
         TagDatabase.save(store)
         return store
     }
@@ -1253,6 +1270,7 @@
     static func recordLauncherOpen(for path: String) {
         var store = TagDatabase.load()
         store.appOpenCounts[path] = (store.appOpenCounts[path] ?? 0) + 1
+        store.appLastOpenedAt[path] = Date()
 
         if store.uncommonSources[path] == .auto,
            store.appOpenCounts[path, default: 0] >= TagDatabase.autoUncommonOpenThreshold {
diff --git a/Apptag/Info.plist b/Apptag/Info.plist
index fc5cc64..796803c 100644
--- a/Apptag/Info.plist
+++ b/Apptag/Info.plist
@@ -19,9 +19,9 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>7.3.5</string>
+	<string>7.5.1</string>
 	<key>CFBundleVersion</key>
-	<string>744</string>
+	<string>751</string>
 	<key>LSMinimumSystemVersion</key>
 	<string>15.0</string>
 	<key>NSHighResolutionCapable</key>
diff --git a/Apptag/Localization/ar-Najdi.json b/Apptag/Localization/ar-Najdi.json
index 555de22..acc328b 100644
--- a/Apptag/Localization/ar-Najdi.json
+++ b/Apptag/Localization/ar-Najdi.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "مخطط البداية الذكي للنظام",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ar.json b/Apptag/Localization/ar.json
index 923f6e1..be9d14c 100644
--- a/Apptag/Localization/ar.json
+++ b/Apptag/Localization/ar.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "مخطط البداية الذكي للنظام",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/cs.json b/Apptag/Localization/cs.json
index 13f25ff..e574f01 100644
--- a/Apptag/Localization/cs.json
+++ b/Apptag/Localization/cs.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Chytré počáteční schéma systému",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/da.json b/Apptag/Localization/da.json
index 0c8254a..faea69c 100644
--- a/Apptag/Localization/da.json
+++ b/Apptag/Localization/da.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Systemets smarte startskema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/de.json b/Apptag/Localization/de.json
index 696c07b..65e3def 100644
--- a/Apptag/Localization/de.json
+++ b/Apptag/Localization/de.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Intelligentes System-Startschema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/en.json b/Apptag/Localization/en.json
index 2be6257..70bdeae 100644
--- a/Apptag/Localization/en.json
+++ b/Apptag/Localization/en.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "System smart initial scheme",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/es.json b/Apptag/Localization/es.json
index 50e9885..0c0aad0 100644
--- a/Apptag/Localization/es.json
+++ b/Apptag/Localization/es.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Esquema inicial inteligente del sistema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/fr.json b/Apptag/Localization/fr.json
index c4c39c5..12fc2da 100644
--- a/Apptag/Localization/fr.json
+++ b/Apptag/Localization/fr.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Schéma initial intelligent du système",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/id.json b/Apptag/Localization/id.json
index 8134636..870fb63 100644
--- a/Apptag/Localization/id.json
+++ b/Apptag/Localization/id.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Skema awal pintar sistem",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/it.json b/Apptag/Localization/it.json
index 0dfa553..7702525 100644
--- a/Apptag/Localization/it.json
+++ b/Apptag/Localization/it.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Schema iniziale intelligente di sistema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ja.json b/Apptag/Localization/ja.json
index ec069c4..f74f5bd 100644
--- a/Apptag/Localization/ja.json
+++ b/Apptag/Localization/ja.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "システム初期スマート分類",
   "settings.bubbleDisplayScope": "吹き出しの表示対象:",
   "settings.bubbleAllApps": "すべてのアプリ",
-  "settings.bubbleUncommonOnly": "あまり使わないアプリのみ"
+  "settings.bubbleUncommonOnly": "あまり使わないアプリのみ",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ko.json b/Apptag/Localization/ko.json
index 844b0df..353341e 100644
--- a/Apptag/Localization/ko.json
+++ b/Apptag/Localization/ko.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "시스템 스마트 초기 분류",
   "settings.bubbleDisplayScope": "말풍선 표시 대상:",
   "settings.bubbleAllApps": "모든 앱",
-  "settings.bubbleUncommonOnly": "자주 쓰지 않는 앱만"
+  "settings.bubbleUncommonOnly": "자주 쓰지 않는 앱만",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ms.json b/Apptag/Localization/ms.json
index c5f57d9..54a3db7 100644
--- a/Apptag/Localization/ms.json
+++ b/Apptag/Localization/ms.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Skema awal pintar sistem",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/nb.json b/Apptag/Localization/nb.json
index 656c969..4241d07 100644
--- a/Apptag/Localization/nb.json
+++ b/Apptag/Localization/nb.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Systemets smarte startskjema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/nl.json b/Apptag/Localization/nl.json
index 1f752ad..56029ab 100644
--- a/Apptag/Localization/nl.json
+++ b/Apptag/Localization/nl.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Slim beginschema van systeem",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/nn.json b/Apptag/Localization/nn.json
index 41227a6..2e59d4c 100644
--- a/Apptag/Localization/nn.json
+++ b/Apptag/Localization/nn.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Systemets smarte startskjema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/no.json b/Apptag/Localization/no.json
index 656c969..4241d07 100644
--- a/Apptag/Localization/no.json
+++ b/Apptag/Localization/no.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Systemets smarte startskjema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/pl.json b/Apptag/Localization/pl.json
index 1ebcbca..0dff021 100644
--- a/Apptag/Localization/pl.json
+++ b/Apptag/Localization/pl.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Inteligentny schemat początkowy systemu",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/pt-BR.json b/Apptag/Localization/pt-BR.json
index 3f20cb4..c542ab2 100644
--- a/Apptag/Localization/pt-BR.json
+++ b/Apptag/Localization/pt-BR.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Esquema inicial inteligente do sistema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ro.json b/Apptag/Localization/ro.json
index bfa075a..0f7d8a5 100644
--- a/Apptag/Localization/ro.json
+++ b/Apptag/Localization/ro.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Schema inteligentă inițială a sistemului",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/ru.json b/Apptag/Localization/ru.json
index a778443..6123e30 100644
--- a/Apptag/Localization/ru.json
+++ b/Apptag/Localization/ru.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Интеллектуальная начальная схема системы",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/sr-Cyrl.json b/Apptag/Localization/sr-Cyrl.json
index ca61f58..97a8b71 100644
--- a/Apptag/Localization/sr-Cyrl.json
+++ b/Apptag/Localization/sr-Cyrl.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Паметна почетна шема система",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/sv.json b/Apptag/Localization/sv.json
index 5c49131..e84b55c 100644
--- a/Apptag/Localization/sv.json
+++ b/Apptag/Localization/sv.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Systemets smarta startschema",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/th.json b/Apptag/Localization/th.json
index 4d4c8f6..80a48ac 100644
--- a/Apptag/Localization/th.json
+++ b/Apptag/Localization/th.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "ชุดเริ่มต้นอัจฉริยะของระบบ",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/tr.json b/Apptag/Localization/tr.json
index 9be388a..7415cb1 100644
--- a/Apptag/Localization/tr.json
+++ b/Apptag/Localization/tr.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Sistem akıllı başlangıç şeması",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/uk.json b/Apptag/Localization/uk.json
index a8e5d2b..4b725ef 100644
--- a/Apptag/Localization/uk.json
+++ b/Apptag/Localization/uk.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Розумна початкова схема системи",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/vi.json b/Apptag/Localization/vi.json
index af84dbf..a168d4b 100644
--- a/Apptag/Localization/vi.json
+++ b/Apptag/Localization/vi.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "Sơ đồ khởi tạo thông minh của hệ thống",
   "settings.bubbleDisplayScope": "Bubble tips show for:",
   "settings.bubbleAllApps": "All apps",
-  "settings.bubbleUncommonOnly": "Uncommon apps only"
+  "settings.bubbleUncommonOnly": "Uncommon apps only",
+  "quickSearch.title": "Quick Search",
+  "quickSearch.placeholder": "Search apps, tags, and notes",
+  "quickSearch.inputAccessibility": "Quick Search input",
+  "quickSearch.emptyPrompt": "Start typing to search apps, tags, and notes.",
+  "quickSearch.noResults": "No apps found.",
+  "quickSearch.launchFailed": "Unable to open this app. Please try again or choose another app.",
+  "quickSearch.tagPrefix": "Tag",
+  "quickSearch.hotkeys": "Keyboard shortcuts",
+  "quickSearch.mainHotkey": "App list",
+  "quickSearch.mainHotkeyDesc": "Opens the TagLauncher app list.",
+  "quickSearch.directHotkey": "Quick Search (global)",
+  "quickSearch.directHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.record": "Change",
+  "quickSearch.recording": "Recording",
+  "quickSearch.clear": "Clear",
+  "quickSearch.restoreDefault": "Restore default",
+  "quickSearch.retry": "Retry registration",
+  "quickSearch.recordingHint": "Press the new global shortcut. Press Esc to cancel.",
+  "quickSearch.disabled": "Disabled",
+  "quickSearch.blocked": "Blocked",
+  "quickSearch.previousStillActive": "Previous shortcut remains active:",
+  "quickSearch.status.Active": "Active",
+  "quickSearch.status.Conflict": "Conflict",
+  "quickSearch.status.Disabled": "Disabled",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space is used by Spotlight. Change Spotlight in macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space is used by the Finder search window. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space is used to switch to the previous input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space is used to switch to the next input source. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space is used for Emoji & Symbols. Change macOS Keyboard Shortcuts, or choose another shortcut.",
+  "quickSearch.hotkeyConflict.generic": "This shortcut is already used by macOS or another app. Choose another shortcut, or change the shortcut in the other app and retry.",
+  "quickSearch.loading": "Preparing search index…",
+  "quickSearch.openKeyboardSettings": "Open macOS Keyboard Shortcuts settings",
+  "quickSearch.internalHotkey": "Quick Search (inside TagLauncher)",
+  "quickSearch.internalHotkeyDesc": "Works only while the TagLauncher app list is open.",
+  "quickSearch.internalHotkeyStatus": "App list only",
+  "quickSearch.globalHotkey": "Quick Search (global)",
+  "quickSearch.globalHotkeyDesc": "Open Quick Search globally when the TagLauncher app list is not visible.",
+  "quickSearch.spaceDisplay": "Space",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space may already be used by macOS input source or Globe/Fn shortcuts. Open macOS Keyboard Shortcuts to change that system shortcut, or choose another shortcut here."
 }
diff --git a/Apptag/Localization/zh-Hans.json b/Apptag/Localization/zh-Hans.json
index 4708a12..d3f85f9 100644
--- a/Apptag/Localization/zh-Hans.json
+++ b/Apptag/Localization/zh-Hans.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "系统智能化初始分类",
   "settings.bubbleDisplayScope": "气泡提示框显示位置:",
   "settings.bubbleAllApps": "全部应用",
-  "settings.bubbleUncommonOnly": "仅不常用应用"
+  "settings.bubbleUncommonOnly": "仅不常用应用",
+  "quickSearch.title": "快捷搜索",
+  "quickSearch.placeholder": "搜索 App、标签和备注",
+  "quickSearch.inputAccessibility": "快捷搜索输入框",
+  "quickSearch.emptyPrompt": "开始输入以搜索 App、标签和备注。",
+  "quickSearch.noResults": "未找到 App。",
+  "quickSearch.launchFailed": "无法打开这个 App。请重试或选择其他 App。",
+  "quickSearch.tagPrefix": "标签",
+  "quickSearch.hotkeys": "快捷键",
+  "quickSearch.mainHotkey": "主界面",
+  "quickSearch.mainHotkeyDesc": "打开 TagLauncher 应用列表。",
+  "quickSearch.directHotkey": "快捷搜索(全局)",
+  "quickSearch.directHotkeyDesc": "不在 TagLauncher 主界面时,直接打开快捷搜索。全局有效。",
+  "quickSearch.record": "修改",
+  "quickSearch.recording": "录制中",
+  "quickSearch.clear": "清除",
+  "quickSearch.restoreDefault": "恢复默认",
+  "quickSearch.retry": "重试注册",
+  "quickSearch.recordingHint": "按下新的全局快捷键。按 Esc 取消。",
+  "quickSearch.disabled": "已关闭",
+  "quickSearch.blocked": "被阻塞",
+  "quickSearch.previousStillActive": "之前可用的快捷键仍保持可用:",
+  "quickSearch.status.Active": "已启用",
+  "quickSearch.status.Conflict": "冲突",
+  "quickSearch.status.Disabled": "已关闭",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space 已被 Spotlight 使用。请在 macOS 键盘快捷键中修改 Spotlight,或选择其他快捷键。",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space 已被 Finder 搜索窗口使用。请在 macOS 键盘快捷键中修改,或选择其他快捷键。",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space 已被“上一个输入法”使用。请在 macOS 键盘快捷键中修改,或选择其他快捷键。",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space 已被“下一个输入法”使用。请在 macOS 键盘快捷键中修改,或选择其他快捷键。",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space 已被“表情与符号”使用。请在 macOS 键盘快捷键中修改,或选择其他快捷键。",
+  "quickSearch.hotkeyConflict.generic": "这个快捷键已被 macOS 或其他 App 使用。请选择其他快捷键,或先修改其他 App 中的快捷键后再重试。",
+  "quickSearch.loading": "正在准备搜索索引…",
+  "quickSearch.openKeyboardSettings": "打开 macOS 键盘快捷键设置",
+  "quickSearch.internalHotkey": "快捷搜索(TagLauncher 内部)",
+  "quickSearch.internalHotkeyDesc": "仅在 TagLauncher 主界面有效。",
+  "quickSearch.internalHotkeyStatus": "仅主界面有效",
+  "quickSearch.globalHotkey": "快捷搜索(全局)",
+  "quickSearch.globalHotkeyDesc": "不在 TagLauncher 主界面时,直接打开快捷搜索。全局有效。",
+  "quickSearch.spaceDisplay": "Space(空格键)",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space 可能已被 macOS 的输入法或地球键快捷键占用。请打开 macOS 键盘快捷键设置关闭或改掉对应系统快捷键,或在这里选择其他组合。"
 }
diff --git a/Apptag/Localization/zh-Hant.json b/Apptag/Localization/zh-Hant.json
index 66c44e1..61b776c 100644
--- a/Apptag/Localization/zh-Hant.json
+++ b/Apptag/Localization/zh-Hant.json
@@ -142,5 +142,44 @@
   "scheme.systemSmartStart": "系統智慧化初始分類",
   "settings.bubbleDisplayScope": "氣泡提示框顯示位置:",
   "settings.bubbleAllApps": "全部 App",
-  "settings.bubbleUncommonOnly": "僅不常用 App"
+  "settings.bubbleUncommonOnly": "僅不常用 App",
+  "quickSearch.title": "快捷搜尋",
+  "quickSearch.placeholder": "搜尋 App、標籤和備註",
+  "quickSearch.inputAccessibility": "快捷搜尋輸入框",
+  "quickSearch.emptyPrompt": "開始輸入以搜尋 App、標籤和備註。",
+  "quickSearch.noResults": "找不到 App。",
+  "quickSearch.launchFailed": "無法打開這個 App。請重試或選擇其他 App。",
+  "quickSearch.tagPrefix": "標籤",
+  "quickSearch.hotkeys": "快捷鍵",
+  "quickSearch.mainHotkey": "主介面",
+  "quickSearch.mainHotkeyDesc": "打開 TagLauncher 應用列表。",
+  "quickSearch.directHotkey": "快捷搜尋(全域)",
+  "quickSearch.directHotkeyDesc": "不在 TagLauncher 主介面時,直接打開快捷搜尋。全域有效。",
+  "quickSearch.record": "修改",
+  "quickSearch.recording": "錄製中",
+  "quickSearch.clear": "清除",
+  "quickSearch.restoreDefault": "恢復預設",
+  "quickSearch.retry": "重試註冊",
+  "quickSearch.recordingHint": "按下新的全域快捷鍵。按 Esc 取消。",
+  "quickSearch.disabled": "已關閉",
+  "quickSearch.blocked": "被阻塞",
+  "quickSearch.previousStillActive": "之前可用的快捷鍵仍保持可用:",
+  "quickSearch.status.Active": "已啟用",
+  "quickSearch.status.Conflict": "衝突",
+  "quickSearch.status.Disabled": "已關閉",
+  "quickSearch.hotkeyConflict.spotlight": "Command + Space 已被 Spotlight 使用。請在 macOS 鍵盤快捷鍵中修改 Spotlight,或選擇其他快捷鍵。",
+  "quickSearch.hotkeyConflict.finderSearch": "Option + Command + Space 已被 Finder 搜尋視窗使用。請在 macOS 鍵盤快捷鍵中修改,或選擇其他快捷鍵。",
+  "quickSearch.hotkeyConflict.previousInput": "Control + Space 已被「上一個輸入法」使用。請在 macOS 鍵盤快捷鍵中修改,或選擇其他快捷鍵。",
+  "quickSearch.hotkeyConflict.nextInput": "Control + Option + Space 已被「下一個輸入法」使用。請在 macOS 鍵盤快捷鍵中修改,或選擇其他快捷鍵。",
+  "quickSearch.hotkeyConflict.emoji": "Control + Command + Space 已被「表情與符號」使用。請在 macOS 鍵盤快捷鍵中修改,或選擇其他快捷鍵。",
+  "quickSearch.hotkeyConflict.generic": "這個快捷鍵已被 macOS 或其他 App 使用。請選擇其他快捷鍵,或先修改其他 App 中的快捷鍵後再重試。",
+  "quickSearch.loading": "正在準備搜尋索引…",
+  "quickSearch.openKeyboardSettings": "打開 macOS 鍵盤快捷鍵設定",
+  "quickSearch.internalHotkey": "快捷搜尋(TagLauncher 內部)",
+  "quickSearch.internalHotkeyDesc": "僅在 TagLauncher 主介面有效。",
+  "quickSearch.internalHotkeyStatus": "僅主介面有效",
+  "quickSearch.globalHotkey": "快捷搜尋(全域)",
+  "quickSearch.globalHotkeyDesc": "不在 TagLauncher 主介面時,直接打開快捷搜尋。全域有效。",
+  "quickSearch.spaceDisplay": "Space(空格鍵)",
+  "quickSearch.hotkeyConflict.fnSpace": "Fn + Space 可能已被 macOS 的輸入法或地球鍵快捷鍵佔用。請打開 macOS 鍵盤快捷鍵設定關閉或改掉對應系統快捷鍵,或在這裡選擇其他組合。"
 }
diff --git a/Apptag/PreferencesView.swift b/Apptag/PreferencesView.swift
index d0a1843..16d4dee 100644
--- a/Apptag/PreferencesView.swift
+++ b/Apptag/PreferencesView.swift
@@ -31,6 +31,9 @@
     @State private var categoryScheme = TagDatabase.CategorySchemeState()
     @State private var isApplyingSystemScheme = false
     @State private var showApplySystemSchemeConfirmation = false
+    @State private var recordingHotkeyKind: LauncherHotkeyKind? = nil
+    @State private var hotkeyCaptureMonitor: Any? = nil
+    @State private var hotkeyRefreshToken = 0
 
     private func scanApps() {
         DispatchQueue.global(qos: .userInitiated).async {
@@ -339,6 +342,130 @@
         .contentShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
     }
 
+    private func applyHotkey(_ hotkey: LauncherHotkey?, for kind: LauncherHotkeyKind) {
+        (NSApp.delegate as? AppDelegate)?.applyHotkey(hotkey, for: kind)
+        hotkeyRefreshToken &+= 1
+    }
+
+    private func retryHotkey(_ kind: LauncherHotkeyKind) {
+        (NSApp.delegate as? AppDelegate)?.retryHotkeyRegistration(for: kind)
+        hotkeyRefreshToken &+= 1
+    }
+
+    private func openKeyboardShortcutsSettings() {
+        let urls = [
+            URL(string: "x-apple.systempreferences:com.apple.Keyboard-Settings.extension?Shortcuts"),
+            URL(string: "x-apple.systempreferences:com.apple.preference.keyboard?shortcuts")
+        ].compactMap { $0 }
+        guard let url = urls.first else { return }
+        NSWorkspace.shared.open(url)
+    }
+
+    private func hotkeySettingsPanel() -> some View {
+        VStack(alignment: .leading, spacing: 12) {
+            HStack {
+                Text(tr("quickSearch.hotkeys"))
+                    .font(.system(size: 13, weight: .semibold))
+                    .foregroundStyle(.secondary)
+                Spacer()
+                Button(action: openKeyboardShortcutsSettings) {
+                    Label(tr("quickSearch.openKeyboardSettings"), systemImage: "keyboard")
+                        .font(.system(size: 13, weight: .semibold))
+                        .lineLimit(1)
+                }
+                .buttonStyle(.bordered)
+                .help(tr("quickSearch.openKeyboardSettings"))
+                .accessibilityLabel(tr("quickSearch.openKeyboardSettings"))
+            }
+
+            HotkeySettingRow(
+                title: tr("quickSearch.mainHotkey"),
+                description: tr("quickSearch.mainHotkeyDesc"),
+                kind: .main,
+                isRecording: recordingHotkeyKind == .main,
+                allowsEditing: false,
+                refreshToken: hotkeyRefreshToken,
+                onBeginRecording: { },
+                onRestoreDefault: nil,
+                onRetry: { },
+                onCancelRecording: cancelHotkeyRecording
+            )
+
+            StaticHotkeyInfoRow(
+                title: tr("quickSearch.internalHotkey"),
+                description: tr("quickSearch.internalHotkeyDesc"),
+                displayText: tr("quickSearch.spaceDisplay"),
+                statusText: tr("quickSearch.internalHotkeyStatus")
+            )
+
+            HotkeySettingRow(
+                title: tr("quickSearch.globalHotkey"),
+                description: tr("quickSearch.globalHotkeyDesc"),
+                kind: .quickSearch,
+                isRecording: recordingHotkeyKind == .quickSearch,
+                allowsEditing: true,
+                refreshToken: hotkeyRefreshToken,
+                onBeginRecording: { beginHotkeyRecording(.quickSearch) },
+                onRestoreDefault: { applyHotkey(.defaultQuickSearch, for: .quickSearch) },
+                onRetry: { retryHotkey(.quickSearch) },
+                onCancelRecording: cancelHotkeyRecording
+            )
+        }
+        .id(hotkeyRefreshToken)
+    }
+
+    private func beginHotkeyRecording(_ kind: LauncherHotkeyKind) {
+        removeHotkeyCaptureMonitor()
+        recordingHotkeyKind = kind
+        postHotkeyRecordingState(active: true)
+        hotkeyCaptureMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in
+            handleCapturedHotkeyEvent(event, for: kind)
+        }
+    }
+
+    private func handleCapturedHotkeyEvent(_ event: NSEvent, for kind: LauncherHotkeyKind) -> NSEvent? {
+        if event.keyCode == UInt16(kVK_Escape) {
+            cancelHotkeyRecording()
+            return nil
+        }
+        guard let hotkey = LauncherHotkey.from(event: event) else {
+            NSSound.beep()
+            return nil
+        }
+        finishHotkeyRecording()
+        applyHotkey(hotkey, for: kind)
+        return nil
+    }
+
+    private func cancelHotkeyRecording() {
+        finishHotkeyRecording()
+    }
+
+    private func finishHotkeyRecording() {
+        guard recordingHotkeyKind != nil || hotkeyCaptureMonitor != nil else { return }
+        recordingHotkeyKind = nil
+        removeHotkeyCaptureMonitor()
+        postHotkeyRecordingState(active: false)
+    }
+
+    private func removeHotkeyCaptureMonitor() {
+        if let hotkeyCaptureMonitor {
+            NSEvent.removeMonitor(hotkeyCaptureMonitor)
+            self.hotkeyCaptureMonitor = nil
+        }
+    }
+
+    private func postHotkeyRecordingState(active: Bool) {
+        NotificationCenter.default.post(
+            name: .tagLauncherModalInteractionChanged,
+            object: nil,
+            userInfo: [
+                "active": active,
+                "source": "hotkeyRecording"
+            ]
+        )
+    }
+
     var body: some View {
         ZStack {
             TabView {
@@ -380,102 +507,112 @@
                     .frame(maxHeight: 250)
 
                     Spacer(minLength: 0)
-                    ShortcutHintView()
-                        .frame(maxWidth: .infinity, alignment: .center)
-                        .padding(.bottom, 2)
                 }
                 .frame(maxWidth: settingsContentWidth, alignment: .leading)
                 .tabItem { Label(tr("settings.language"), systemImage: "globe") }
                 .padding()
 
                 // Tab 2: General
-            VStack(alignment: .leading, spacing: 0) {
-                // Toggle row — centered as a rectangular block
-                HStack(spacing: 20) {
-                    if AppDelegate.supportsLaunchAtLogin {
-                        Toggle(tr("settings.launchAtLogin"), isOn: $launchAtLogin)
-                            .onChange(of: launchAtLogin) { _, enabled in
-                                if enabled {
-                                    AppDelegate.enableLaunchAtLogin()
-                                } else {
-                                    AppDelegate.disableLaunchAtLogin()
+                ScrollView(.vertical, showsIndicators: true) {
+                    VStack(alignment: .leading, spacing: 0) {
+                        // Toggle row — centered as a rectangular block
+                        HStack(spacing: 20) {
+                            if AppDelegate.supportsLaunchAtLogin {
+                                Toggle(tr("settings.launchAtLogin"), isOn: $launchAtLogin)
+                                    .onChange(of: launchAtLogin) { _, enabled in
+                                        if enabled {
+                                            AppDelegate.enableLaunchAtLogin()
+                                        } else {
+                                            AppDelegate.disableLaunchAtLogin()
+                                        }
+                                    }
+                            }
+                            Toggle(tr("settings.showInDock"), isOn: $showDockIcon)
+                                .onChange(of: showDockIcon) { _, _ in
+                                    AppDelegate.refreshChromeSettings()
                                 }
-                            }
-                    }
-                    Toggle(tr("settings.showInDock"), isOn: $showDockIcon)
-                        .onChange(of: showDockIcon) { _, _ in
-                            AppDelegate.refreshChromeSettings()
+                            Toggle(tr("settings.hideAppNames"), isOn: $hideAppNames)
                         }
-                    Toggle(tr("settings.hideAppNames"), isOn: $hideAppNames)
-                }
-                .frame(maxWidth: .infinity, alignment: .center)
-                .padding(.bottom, 16)
+                        .frame(maxWidth: .infinity, alignment: .center)
+                        .padding(.bottom, 16)
 
-                Divider()
-                    .padding(.bottom, 16)
+                        Divider()
+                            .padding(.bottom, 16)
 
-                VStack(spacing: 18) {
-                    generalSettingRow(tr("settings.appListStyle"), description: tr("settings.flatDesc")) {
-                        VStack(spacing: 8) {
-                            DisplayModeOptionButton(
-                                mode: "flat",
-                                title: tr("settings.flat"),
-                                isSelected: displayMode == "flat"
-                            ) {
-                                displayMode = "flat"
-                            }
-
-                            LazyVGrid(columns: displayModeColumns, alignment: .leading, spacing: 8) {
-                                ForEach(containerDisplayModeOptions, id: \.id) { option in
+                        VStack(spacing: 18) {
+                            generalSettingRow(tr("settings.appListStyle"), description: tr("settings.flatDesc")) {
+                                VStack(spacing: 8) {
                                     DisplayModeOptionButton(
-                                        mode: option.id,
-                                        title: option.title,
-                                        isSelected: displayMode == option.id
+                                        mode: "flat",
+                                        title: tr("settings.flat"),
+                                        isSelected: displayMode == "flat"
                                     ) {
-                                        displayMode = option.id
+                                        displayMode = "flat"
+                                    }
+
+                                    LazyVGrid(columns: displayModeColumns, alignment: .leading, spacing: 8) {
+                                        ForEach(containerDisplayModeOptions, id: \.id) { option in
+                                            DisplayModeOptionButton(
+                                                mode: option.id,
+                                                title: option.title,
+                                                isSelected: displayMode == option.id
+                                            ) {
+                                                displayMode = option.id
+                                            }
+                                        }
                                     }
                                 }
+                                .frame(width: generalControlWidth, alignment: .leading)
+                            }
+
+                            generalSettingRow(tr("settings.tagPosition"), description: tr("settings.tagPosDesc")) {
+                                Picker("", selection: $tagPosition) {
+                                    Text(tr("settings.left")).tag("left")
+                                    Text(tr("settings.right")).tag("right")
+                                    Text(tr("settings.top")).tag("top")
+                                }
+                                .pickerStyle(.segmented)
+                                .frame(width: compactPickerWidth, alignment: .leading)
+                            }
+
+                            generalSettingRow(tr("settings.tagFontSize"), description: tr("settings.tagFontDesc")) {
+                                Picker("", selection: $tagFontSize) {
+                                    ForEach([16.0, 18.0, 20.0, 22.0, 24.0, 26.0], id: \.self) { size in
+                                        Text("\(Int(size))").tag(size)
+                                    }
+                                }
+                                .pickerStyle(.segmented)
+                                .frame(width: compactPickerWidth, alignment: .leading)
+                            }
+
+                            generalSettingRow(tr("settings.iconSize"), description: tr("settings.iconSizeDesc")) {
+                                Picker("", selection: $iconSize) {
+                                    ForEach([40.0, 48.0, 56.0, 64.0, 72.0, 80.0], id: \.self) { size in
+                                        Text("\(Int(size))").tag(size)
+                                    }
+                                }
+                                .pickerStyle(.segmented)
+                                .frame(width: compactPickerWidth, alignment: .leading)
                             }
                         }
-                        .frame(width: generalControlWidth, alignment: .leading)
                     }
-
-                    generalSettingRow(tr("settings.tagPosition"), description: tr("settings.tagPosDesc")) {
-                        Picker("", selection: $tagPosition) {
-                            Text(tr("settings.left")).tag("left")
-                            Text(tr("settings.right")).tag("right")
-                            Text(tr("settings.top")).tag("top")
-                        }
-                        .pickerStyle(.segmented)
-                        .frame(width: compactPickerWidth, alignment: .leading)
-                    }
-
-                    generalSettingRow(tr("settings.tagFontSize"), description: tr("settings.tagFontDesc")) {
-                        Picker("", selection: $tagFontSize) {
-                            ForEach([16.0, 18.0, 20.0, 22.0, 24.0, 26.0], id: \.self) { size in
-                                Text("\(Int(size))").tag(size)
-                            }
-                        }
-                        .pickerStyle(.segmented)
-                        .frame(width: compactPickerWidth, alignment: .leading)
-                    }
-
-                    generalSettingRow(tr("settings.iconSize"), description: tr("settings.iconSizeDesc")) {
-                        Picker("", selection: $iconSize) {
-                            ForEach([40.0, 48.0, 56.0, 64.0, 72.0, 80.0], id: \.self) { size in
-                                Text("\(Int(size))").tag(size)
-                            }
-                        }
-                        .pickerStyle(.segmented)
-                        .frame(width: compactPickerWidth, alignment: .leading)
-                    }
+                    .frame(maxWidth: generalContentWidth, alignment: .center)
+                    .padding()
                 }
-            }
-            .frame(maxWidth: generalContentWidth, alignment: .center)
-            .padding()
-            .tabItem { Label(tr("settings.general"), systemImage: "gearshape") }
+                .tabItem { Label(tr("settings.general"), systemImage: "gearshape") }
 
-            // Tab 3: Tags
+            // Tab 3: Hotkeys
+            ScrollView(.vertical, showsIndicators: true) {
+                VStack(alignment: .leading, spacing: 16) {
+                    hotkeySettingsPanel()
+                        .frame(width: generalContentWidth, alignment: .leading)
+                }
+                .frame(maxWidth: generalContentWidth, alignment: .center)
+                .padding()
+            }
+            .tabItem { Label(tr("quickSearch.hotkeys"), systemImage: "keyboard") }
+
+            // Tab 4: Tags
             VStack(spacing: 0) {
                 TagEditorView(
                     tagColors: $tagColors,
@@ -486,7 +623,7 @@
             .tabItem { Label(tr("settings.tags"), systemImage: "tag.fill") }
             .onAppear { scanApps() }
 
-            // Tab 4: Data
+            // Tab 5: Data
             VStack(spacing: 0) {
                 Spacer(minLength: 32)
 
@@ -626,7 +763,7 @@
             .padding()
             .onAppear { refreshDataState() }
 
-            // Tab 5: About
+            // Tab 6: About
             VStack(spacing: 0) {
                 Spacer(minLength: 72)
 
@@ -661,8 +798,6 @@
                 .frame(width: 560, alignment: .leading)
 
                 Spacer(minLength: 30)
-                ShortcutHintView()
-                    .frame(maxWidth: .infinity, alignment: .center)
                 Spacer(minLength: 18)
             }
             .tabItem { Label(tr("settings.about"), systemImage: "info.circle") }
@@ -683,6 +818,9 @@
             }
             .onReceive(NotificationCenter.default.publisher(for: .tagLauncherDataDidChange)) { _ in
                 refreshDataState()
+            }
+            .onReceive(NotificationCenter.default.publisher(for: .tagLauncherHotkeysChanged)) { _ in
+                hotkeyRefreshToken &+= 1
             }
 
             if isRefreshingLanguage {
@@ -718,6 +856,9 @@
         .onAppear {
             syncSelectedLanguage()
         }
+        .onDisappear {
+            finishHotkeyRecording()
+        }
     }
 
     private func showLanguageRefresh() {
@@ -727,6 +868,250 @@
                 isRefreshingLanguage = false
             }
         }
+    }
+}
+
+private struct StaticHotkeyInfoRow: View {
+    let title: String
+    let description: String
+    let displayText: String
+    let statusText: String
+
+    var body: some View {
+        VStack(alignment: .leading, spacing: 12) {
+            HStack(alignment: .top, spacing: 12) {
+                VStack(alignment: .leading, spacing: 3) {
+                    Text(title)
+                        .font(.system(size: 13, weight: .semibold))
+                    Text(description)
+                        .font(.caption)
+                        .foregroundStyle(.secondary)
+                        .fixedSize(horizontal: false, vertical: true)
+                }
+                .frame(maxWidth: .infinity, alignment: .leading)
+
+                VStack(alignment: .leading, spacing: 4) {
+                    Text(displayText)
+                        .font(.system(size: 15, weight: .semibold))
+                        .lineLimit(1)
+                        .minimumScaleFactor(0.85)
+                    Text(statusText)
+                        .font(.system(size: 11, weight: .semibold))
+                        .foregroundStyle(Color.secondary)
+                        .padding(.horizontal, 8)
+                        .padding(.vertical, 3)
+                        .background(Capsule().fill(Color.secondary.opacity(0.13)))
+                }
+                .frame(width: 180, alignment: .leading)
+            }
+        }
+        .padding(12)
+        .background(
+            RoundedRectangle(cornerRadius: 8, style: .continuous)
+                .fill(Color(nsColor: .controlBackgroundColor))
+        )
+        .overlay(
+            RoundedRectangle(cornerRadius: 8, style: .continuous)
+                .stroke(Color.secondary.opacity(0.14), lineWidth: 1)
+        )
+    }
+}
+
+private struct HotkeySettingRow: View {
+    let title: String
+    let description: String
+    let kind: LauncherHotkeyKind
+    let isRecording: Bool
+    let allowsEditing: Bool
+    let refreshToken: Int
+    let onBeginRecording: () -> Void
+    let onRestoreDefault: (() -> Void)?
+    let onRetry: () -> Void
+    let onCancelRecording: () -> Void
+
+    private var activeHotkey: LauncherHotkey? {
+        _ = refreshToken
+        return LauncherHotkeyStore.hotkey(for: kind)
+    }
+
+    private var pendingHotkey: LauncherHotkey? {
+        _ = refreshToken
+        return LauncherHotkeyStore.pendingHotkey(for: kind)
+    }
+
+    private var status: LauncherHotkeyStatus {
+        _ = refreshToken
+        return LauncherHotkeyStore.status(for: kind)
+    }
+
+    private var conflictMessage: String {
+        _ = refreshToken
+        return LauncherHotkeyStore.conflictMessage(for: kind)
+    }
+
+    var body: some View {
+        VStack(alignment: .leading, spacing: 12) {
+            HStack(alignment: .top, spacing: 12) {
+                VStack(alignment: .leading, spacing: 3) {
+                    Text(title)
+                        .font(.system(size: 13, weight: .semibold))
+                    Text(description)
+                        .font(.caption)
+                        .foregroundStyle(.secondary)
+                        .fixedSize(horizontal: false, vertical: true)
+                }
+                .frame(maxWidth: .infinity, alignment: .leading)
+
+                VStack(alignment: .leading, spacing: 4) {
+                    Text(displayText)
+                        .font(.system(size: 15, weight: .semibold))
+                        .lineLimit(1)
+                        .minimumScaleFactor(0.85)
+                    statusLabel
+                }
+                .frame(width: 180, alignment: .leading)
+            }
+
+            if allowsEditing {
+                HStack(spacing: 8) {
+                    hotkeyButton(
+                        isRecording ? tr("quickSearch.recording") : tr("quickSearch.record"),
+                        systemImage: isRecording ? "keyboard.badge.ellipsis" : "keyboard",
+                        prominent: true,
+                        action: onBeginRecording
+                    )
+                    if let onRestoreDefault {
+                        hotkeyButton(
+                            tr("quickSearch.restoreDefault"),
+                            systemImage: "arrow.counterclockwise",
+                            prominent: false,
+                            action: onRestoreDefault
+                        )
+                    }
+                    if status == .conflict {
+                        hotkeyButton(
+                            tr("quickSearch.retry"),
+                            systemImage: "arrow.clockwise",
+                            prominent: false,
+                            action: onRetry
+                        )
+                    }
+                    Spacer(minLength: 0)
+                }
+            }
+
+            if allowsEditing && isRecording {
+                HStack(spacing: 8) {
+                    Image(systemName: "keyboard")
+                    Text(tr("quickSearch.recordingHint"))
+                    Spacer(minLength: 0)
+                    Button(tr("settings.cancel"), action: onCancelRecording)
+                        .buttonStyle(.borderless)
+                }
+                .font(.system(size: 13, weight: .semibold))
+                .foregroundStyle(Color.accentColor)
+                .padding(.horizontal, 10)
+                .padding(.vertical, 10)
+                .background(RoundedRectangle(cornerRadius: 7).fill(Color.accentColor.opacity(0.10)))
+            }
+
+            if status == .conflict && !conflictMessage.isEmpty {
+                HotkeyConflictNotice(text: conflictDetailText)
+            }
+        }
+        .padding(12)
+        .background(
+            RoundedRectangle(cornerRadius: 8, style: .continuous)
+                .fill(Color(nsColor: .controlBackgroundColor))
+        )
+        .overlay(
+            RoundedRectangle(cornerRadius: 8, style: .continuous)
+                .stroke(Color.secondary.opacity(0.14), lineWidth: 1)
+        )
+    }
+
+    private var displayText: String {
+        if status == .conflict, let pendingHotkey {
+            return "\(pendingHotkey.displayString) · \(tr("quickSearch.blocked"))"
+        }
+        return activeHotkey?.displayString ?? tr("quickSearch.disabled")
+    }
+
+    private var conflictDetailText: String {
+        if let activeHotkey {
+            return "\(conflictMessage) \(tr("quickSearch.previousStillActive")) \(activeHotkey.displayString)"
+        }
+        return conflictMessage
+    }
+
+    private var statusLabel: some View {
+        Text(tr("quickSearch.status.\(status.rawValue)"))
+            .font(.system(size: 11, weight: .semibold))
+            .foregroundStyle(statusColor)
+            .padding(.horizontal, 8)
+            .padding(.vertical, 3)
+            .background(Capsule().fill(statusColor.opacity(0.13)))
+    }
+
+    private var statusColor: Color {
+        switch status {
+        case .active: return .green
+        case .conflict: return .orange
+        case .disabled: return .secondary
+        }
+    }
+
+    private func hotkeyButton(
+        _ title: String,
+        systemImage: String,
+        prominent: Bool,
+        action: @escaping () -> Void
+    ) -> some View {
+        Button(action: action) {
+            Label(title, systemImage: systemImage)
+                .font(.system(size: 13, weight: .semibold))
+                .lineLimit(1)
+                .minimumScaleFactor(0.88)
+                .foregroundStyle(prominent ? Color.white : Color.primary)
+                .padding(.horizontal, 10)
+                .frame(height: 30)
+                .background(
+                    RoundedRectangle(cornerRadius: 7, style: .continuous)
+                        .fill(prominent ? Color.accentColor : Color(nsColor: .controlBackgroundColor))
+                )
+                .overlay(
+                    RoundedRectangle(cornerRadius: 7, style: .continuous)
+                        .stroke(prominent ? Color.accentColor.opacity(0.24) : Color.secondary.opacity(0.22), lineWidth: 1)
+                )
+        }
+        .buttonStyle(.plain)
+        .help(title)
+        .accessibilityLabel(title)
+    }
+}
+
+private struct HotkeyConflictNotice: View {
+    let text: String
+
+    var body: some View {
+        HStack(alignment: .top, spacing: 8) {
+            Image(systemName: "exclamationmark.triangle.fill")
+                .font(.system(size: 13, weight: .semibold))
+                .foregroundStyle(Color.white.opacity(0.94))
+                .padding(.top, 1)
+            Text(text)
+                .font(.system(size: 12, weight: .medium))
+                .foregroundStyle(Color.white)
+                .fixedSize(horizontal: false, vertical: true)
+            Spacer(minLength: 0)
+        }
+        .padding(.horizontal, 10)
+        .padding(.vertical, 9)
+        .background(
+            RoundedRectangle(cornerRadius: 8, style: .continuous)
+                .fill(Color.black.opacity(0.92))
+        )
+        .shadow(color: .black.opacity(0.24), radius: 16, y: 8)
     }
 }
 
@@ -924,60 +1309,5 @@
         }
         let palette: [Color] = [.green, .purple, .blue, .orange]
         return palette[index % palette.count].opacity(0.78)
-    }
-}
-
-private struct ShortcutHintView: View {
-    var body: some View {
-        HStack(spacing: 12) {
-            ShortcutKeycap(symbol: "⌥")
-            Text("+")
-                .font(.system(size: 22, weight: .semibold))
-                .foregroundStyle(.tertiary)
-            ShortcutKeycap(symbol: "⇧")
-            Text("+")
-                .font(.system(size: 22, weight: .semibold))
-                .foregroundStyle(.tertiary)
-            SpacebarKeycap()
-        }
-        .accessibilityLabel("⌥ ⇧ Space")
-        .allowsHitTesting(false)
-    }
-}
-
-private struct ShortcutKeycap: View {
-    let symbol: String
-
-    var body: some View {
-        Text(symbol)
-            .font(.system(size: 36, weight: .medium))
-            .foregroundStyle(.secondary)
-            .frame(width: 74, height: 58)
-            .background(KeycapBackground())
-    }
-}
-
-private struct SpacebarKeycap: View {
-    var body: some View {
-        ZStack {
-            KeycapBackground()
-            Capsule()
-                .fill(Color.secondary.opacity(0.38))
-                .frame(width: 72, height: 3)
-                .offset(y: 13)
-        }
-        .frame(width: 190, height: 58)
-    }
-}
-
-private struct KeycapBackground: View {
-    var body: some View {
-        RoundedRectangle(cornerRadius: 10, style: .continuous)
-            .fill(Color(nsColor: .controlBackgroundColor))
-            .overlay(
-                RoundedRectangle(cornerRadius: 10, style: .continuous)
-                    .stroke(Color.primary.opacity(0.12), lineWidth: 1)
-            )
-            .shadow(color: .black.opacity(0.10), radius: 8, x: 0, y: 3)
     }
 }
diff --git a/Apptag/QuickSearch.swift b/Apptag/QuickSearch.swift
new file mode 100644
index 0000000..679f4c6
--- /dev/null
+++ b/Apptag/QuickSearch.swift
@@ -0,0 +1,1080 @@
+import SwiftUI
+import AppKit
+import Carbon
+
+extension Notification.Name {
+    static let tagLauncherQuickSearchRequested = Notification.Name("TagLauncherQuickSearchRequested")
+    static let tagLauncherQuickSearchDismissRequested = Notification.Name("TagLauncherQuickSearchDismissRequested")
+    static let tagLauncherQuickSearchVisibilityChanged = Notification.Name("TagLauncherQuickSearchVisibilityChanged")
+    static let tagLauncherHotkeysChanged = Notification.Name("TagLauncherHotkeysChanged")
+}
+
+enum QuickSearchOpenSource {
+    static let mainOverlay = "mainOverlay"
+    static let globalHidden = "globalHidden"
+    static let globalVisible = "globalVisible"
+}
+
+// MARK: - Hotkeys
+
+struct LauncherHotkey: Equatable {
+    let keyCode: UInt32
+    let modifiers: UInt32
+
+    var serialized: String {
+        "\(keyCode):\(modifiers)"
+    }
+
+    var displayString: String {
+        let ordered: [(UInt32, String)] = [
+            (UInt32(controlKey), "⌃"),
+            (UInt32(optionKey), "⌥"),
+            (UInt32(shiftKey), "⇧"),
+            (UInt32(cmdKey), "⌘"),
+            (UInt32(kEventKeyModifierFnMask), "Fn+")
+        ]
+        let modifierGlyphs = ordered
+            .filter { modifiers & $0.0 != 0 }
+            .map(\.1)
+            .joined()
+        return modifierGlyphs + LauncherHotkey.keyDisplayName(for: keyCode)
+    }
+
+    static var defaultMain: LauncherHotkey {
+        LauncherHotkey(keyCode: UInt32(kVK_Space), modifiers: UInt32(shiftKey | optionKey))
+    }
+
+    static var defaultQuickSearch: LauncherHotkey {
+        LauncherHotkey(keyCode: UInt32(kVK_Space), modifiers: UInt32(kEventKeyModifierFnMask))
+    }
+
+    static func deserialize(_ value: String?) -> LauncherHotkey? {
+        guard let value, !value.isEmpty else { return nil }
+        let parts = value.split(separator: ":")
+        guard parts.count == 2,
+              let keyCode = UInt32(parts[0]),
+              let modifiers = UInt32(parts[1])
+        else { return nil }
+        return LauncherHotkey(keyCode: keyCode, modifiers: modifiers)
+    }
+
+    static func from(event: NSEvent) -> LauncherHotkey? {
+        let ignoredKeyCodes: Set<UInt16> = [54, 55, 56, 57, 58, 59, 60, 61, 62, 63]
+        guard !ignoredKeyCodes.contains(event.keyCode) else { return nil }
+
+        var carbonModifiers: UInt32 = 0
+        if event.modifierFlags.contains(.shift) { carbonModifiers |= UInt32(shiftKey) }
+        if event.modifierFlags.contains(.option) { carbonModifiers |= UInt32(optionKey) }
+        if event.modifierFlags.contains(.control) { carbonModifiers |= UInt32(controlKey) }
+        if event.modifierFlags.contains(.command) { carbonModifiers |= UInt32(cmdKey) }
+        if event.modifierFlags.contains(.function) { carbonModifiers |= UInt32(kEventKeyModifierFnMask) }
+        guard carbonModifiers != 0 else { return nil }
+
+        return LauncherHotkey(keyCode: UInt32(event.keyCode), modifiers: carbonModifiers)
+    }
+
+    static func keyDisplayName(for keyCode: UInt32) -> String {
+        switch Int(keyCode) {
+        case kVK_Space: return "Space"
+        case kVK_Return: return "Return"
+        case kVK_Escape: return "Esc"
+        case kVK_Delete: return "Delete"
+        case kVK_Tab: return "Tab"
+        case kVK_LeftArrow: return "←"
+        case kVK_RightArrow: return "→"
+        case kVK_UpArrow: return "↑"
+        case kVK_DownArrow: return "↓"
+        case kVK_F1: return "F1"
+        case kVK_F2: return "F2"
+        case kVK_F3: return "F3"
+        case kVK_F4: return "F4"
+        case kVK_F5: return "F5"
+        case kVK_F6: return "F6"
+        case kVK_F7: return "F7"
+        case kVK_F8: return "F8"
+        case kVK_F9: return "F9"
+        case kVK_F10: return "F10"
+        case kVK_F11: return "F11"
+        case kVK_F12: return "F12"
+        default:
+            if let scalar = keyCodeToPrintableScalar[Int(keyCode)] {
+                return String(scalar)
+            }
+            return "Key \(keyCode)"
+        }
+    }
+
+    private static let keyCodeToPrintableScalar: [Int: Character] = [
+        kVK_ANSI_A: "A", kVK_ANSI_B: "B", kVK_ANSI_C: "C", kVK_ANSI_D: "D",
+        kVK_ANSI_E: "E", kVK_ANSI_F: "F", kVK_ANSI_G: "G", kVK_ANSI_H: "H",
+        kVK_ANSI_I: "I", kVK_ANSI_J: "J", kVK_ANSI_K: "K", kVK_ANSI_L: "L",
+        kVK_ANSI_M: "M", kVK_ANSI_N: "N", kVK_ANSI_O: "O", kVK_ANSI_P: "P",
+        kVK_ANSI_Q: "Q", kVK_ANSI_R: "R", kVK_ANSI_S: "S", kVK_ANSI_T: "T",
+        kVK_ANSI_U: "U", kVK_ANSI_V: "V", kVK_ANSI_W: "W", kVK_ANSI_X: "X",
+        kVK_ANSI_Y: "Y", kVK_ANSI_Z: "Z", kVK_ANSI_0: "0", kVK_ANSI_1: "1",
+        kVK_ANSI_2: "2", kVK_ANSI_3: "3", kVK_ANSI_4: "4", kVK_ANSI_5: "5",
+        kVK_ANSI_6: "6", kVK_ANSI_7: "7", kVK_ANSI_8: "8", kVK_ANSI_9: "9"
+    ]
+}
+
+enum LauncherHotkeyKind: String {
+    case main
+    case quickSearch
+
+    var storageKey: String {
+        switch self {
+        case .main: return "mainHotkey"
+        case .quickSearch: return "quickSearchHotkey"
+        }
+    }
+
+    var statusKey: String {
+        switch self {
+        case .main: return "mainHotkeyStatus"
+        case .quickSearch: return "quickSearchHotkeyStatus"
+        }
+    }
+
+    var conflictMessageKey: String {
+        switch self {
+        case .main: return "mainHotkeyConflictMessage"
+        case .quickSearch: return "quickSearchHotkeyConflictMessage"
+        }
+    }
+
+    var pendingStorageKey: String {
+        switch self {
+        case .main: return "mainHotkeyPending"
+        case .quickSearch: return "quickSearchHotkeyPending"
+        }
+    }
+
+    var eventID: UInt32 {
+        switch self {
+        case .main: return 1
+        case .quickSearch: return 2
+        }
+    }
+}
+
+enum LauncherHotkeyStatus: String {
+    case active = "Active"
+    case conflict = "Conflict"
+    case disabled = "Disabled"
+}
+
+enum LauncherHotkeyStore {
+    static func hotkey(for kind: LauncherHotkeyKind) -> LauncherHotkey? {
+        if kind == .main {
+            return .defaultMain
+        }
+        if kind == .quickSearch && !AppDefaults.hasStoredValue(for: kind.storageKey) {
+            return .defaultQuickSearch
+        }
+        return LauncherHotkey.deserialize(UserDefaults.standard.string(forKey: kind.storageKey))
+    }
+
+    static func save(_ hotkey: LauncherHotkey?, for kind: LauncherHotkeyKind) {
+        UserDefaults.standard.set(hotkey?.serialized ?? "", forKey: kind.storageKey)
+        UserDefaults.standard.removeObject(forKey: kind.pendingStorageKey)
+    }
+
+    static func savePending(_ hotkey: LauncherHotkey, for kind: LauncherHotkeyKind) {
+        UserDefaults.standard.set(hotkey.serialized, forKey: kind.pendingStorageKey)
+    }
+
+    static func pendingHotkey(for kind: LauncherHotkeyKind) -> LauncherHotkey? {
+        LauncherHotkey.deserialize(UserDefaults.standard.string(forKey: kind.pendingStorageKey))
+    }
+
+    static func status(for kind: LauncherHotkeyKind) -> LauncherHotkeyStatus {
+        let raw = UserDefaults.standard.string(forKey: kind.statusKey)
+        return LauncherHotkeyStatus(rawValue: raw ?? "") ?? (hotkey(for: kind) == nil ? .disabled : .active)
+    }
+
+    static func setStatus(_ status: LauncherHotkeyStatus, message: String?, for kind: LauncherHotkeyKind) {
+        UserDefaults.standard.set(status.rawValue, forKey: kind.statusKey)
+        if let message, !message.isEmpty {
+            UserDefaults.standard.set(message, forKey: kind.conflictMessageKey)
+        } else {
+            UserDefaults.standard.removeObject(forKey: kind.conflictMessageKey)
+        }
+        NotificationCenter.default.post(name: .tagLauncherHotkeysChanged, object: nil)
+    }
+
+    static func conflictMessage(for kind: LauncherHotkeyKind) -> String {
+        UserDefaults.standard.string(forKey: kind.conflictMessageKey) ?? ""
+    }
+
+    static func knownConflictMessage(for hotkey: LauncherHotkey, status: OSStatus) -> String? {
+        guard status != noErr else { return nil }
+        switch (hotkey.keyCode, hotkey.modifiers) {
+        case (UInt32(kVK_Space), UInt32(cmdKey)):
+            return tr("quickSearch.hotkeyConflict.spotlight")
+        case (UInt32(kVK_Space), UInt32(optionKey | cmdKey)):
+            return tr("quickSearch.hotkeyConflict.finderSearch")
+        case (UInt32(kVK_Space), UInt32(controlKey)):
+            return tr("quickSearch.hotkeyConflict.previousInput")
+        case (UInt32(kVK_Space), UInt32(controlKey | optionKey)):
+            return tr("quickSearch.hotkeyConflict.nextInput")
+        case (UInt32(kVK_Space), UInt32(controlKey | cmdKey)):
+            return tr("quickSearch.hotkeyConflict.emoji")
+        case (UInt32(kVK_Space), UInt32(kEventKeyModifierFnMask)):
+            return tr("quickSearch.hotkeyConflict.fnSpace")
+        default:
+            return nil
+        }
+    }
+}
+
+// MARK: - Search Documents
+
+struct QuickSearchDocument: Identifiable {
+    var id: URL { app.id }
+    let app: AppInfo
+    let localizedNames: [String]
+    let internalBundleNames: [String]
+    let tagNames: [String]
+    let note: String
+    let bundleIdentifier: String
+    let lastOpenedAt: Date?
+    let openCount: Int
+}
+
+struct QuickSearchResult: Identifiable {
+    var id: URL { document.id }
+    let document: QuickSearchDocument
+    let finalScore: Double
+    let textScore: Double
+    let bestFieldRank: Int
+    let matchedTagName: String?
+    let noteSnippet: String?
+
+    var app: AppInfo { document.app }
+}
+
+enum QuickSearchEngine {
+    private enum FieldKind: Int {
+        case name = 0
+        case tag = 1
+        case note = 2
+        case bundleIdentifier = 3
+        case internalBundleName = 4
+
+        var weight: Double {
+            switch self {
+            case .name: return 100
+            case .tag: return 70
+            case .note: return 45
+            case .internalBundleName: return 30
+            case .bundleIdentifier: return 20
+            }
+        }
+    }
+
+    private enum MatchKind {
+        case exact
+        case prefix
+        case substring
+        case acronym
+        case fuzzy
+
+        var weight: Double {
+            switch self {
+            case .exact: return 100
+            case .prefix: return 80
+            case .substring: return 60
+            case .acronym: return 55
+            case .fuzzy: return 35
+            }
+        }
+    }
+
+    private struct Field {
+        let kind: FieldKind
+        let text: String
+        let normalized: String
+        let acronym: String
+        let pinyinCandidates: [String]
+    }
+
+    private struct MatchOptions {
+        let allowSubstring: Bool
+        let allowFuzzySubsequence: Bool
+    }
+
+    private struct TokenMatch {
+        let score: Double
+        let fieldRank: Int
+        let fieldKind: FieldKind
+        let originalText: String
+    }
+
+    static func makeDocuments(apps: [AppInfo], store: TagDatabase.Store) -> [QuickSearchDocument] {
+        apps.map { app in
+            QuickSearchDocument(
+                app: app,
+                localizedNames: localizedNames(for: app),
+                internalBundleNames: internalBundleNames(for: app),
+                tagNames: app.tags,
+                note: store.appNotes[app.path.path] ?? app.note ?? "",
+                bundleIdentifier: app.bundleIdentifier ?? "",
+                lastOpenedAt: store.appLastOpenedAt[app.path.path],
+                openCount: store.appOpenCounts[app.path.path] ?? 0
+            )
+        }
+    }
+
+    static func search(_ query: String, documents: [QuickSearchDocument], limit: Int = 50) -> [QuickSearchResult] {
+        let normalizedQuery = normalizeQuery(query)
+        guard !normalizedQuery.isEmpty else {
+            return emptyQueryResults(documents: documents, limit: min(limit, 6))
+        }
+
+        let tokens = normalizedQuery.split(separator: " ").map(String.init)
+        let results = documents.compactMap { result(for: $0, tokens: tokens) }
+        return results.sorted(by: rank).prefix(limit).map { $0 }
+    }
+
+    static func normalizeQuery(_ value: String) -> String {
+        value
+            .trimmingCharacters(in: .whitespacesAndNewlines)
+            .components(separatedBy: .whitespacesAndNewlines)
+            .filter { !$0.isEmpty }
+            .joined(separator: " ")
+            .folding(options: [.caseInsensitive, .diacriticInsensitive], locale: .current)
+            .lowercased()
+    }
+
+    private static func result(for document: QuickSearchDocument, tokens: [String]) -> QuickSearchResult? {
+        let fields = searchableFields(for: document)
+        var textScore: Double = 0
+        var bestFieldRank = Int.max
+        var matchedTagName: String?
+        var noteSnippet: String?
+
+        for token in tokens {
+            guard let tokenMatch = fields
+                .compactMap({ match(token: token, field: $0) })
+                .max(by: { $0.score < $1.score })
+            else {
+                return nil
+            }
+            textScore += tokenMatch.score
+            bestFieldRank = min(bestFieldRank, tokenMatch.fieldRank)
+            if tokenMatch.fieldKind == .tag {
+                matchedTagName = tokenMatch.originalText
+            } else if tokenMatch.fieldKind == .note {
+                noteSnippet = snippet(from: document.note, token: token)
+            }
+        }
+
+        let finalScore = textScore + behaviorBoost(for: document)
+        return QuickSearchResult(
+            document: document,
+            finalScore: finalScore,
+            textScore: textScore,
+            bestFieldRank: bestFieldRank,
+            matchedTagName: matchedTagName,
+            noteSnippet: noteSnippet
+        )
+    }
+
+    private static func searchableFields(for document: QuickSearchDocument) -> [Field] {
+        let names = uniqueOrdered([document.app.name] + document.localizedNames)
+        let nameFields = names.map {
+            Field(
+                kind: .name,
+                text: $0,
+                normalized: normalizeField($0),
+                acronym: acronym(for: $0),
+                pinyinCandidates: pinyinCandidates(for: $0)
+            )
+        }
+        let tagFields = document.tagNames.map {
+            Field(
+                kind: .tag,
+                text: $0,
+                normalized: normalizeField($0),
+                acronym: "",
+                pinyinCandidates: pinyinCandidates(for: $0)
+            )
+        }
+        let noteFields = document.note.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? [] : [
+            Field(
+                kind: .note,
+                text: document.note,
+                normalized: normalizeField(document.note),
+                acronym: "",
+                pinyinCandidates: pinyinCandidates(for: document.note)
+            )
+        ]
+        let bundleFields = document.bundleIdentifier.isEmpty ? [] : [
+            Field(
+                kind: .bundleIdentifier,
+                text: document.bundleIdentifier,
+                normalized: normalizeField(document.bundleIdentifier),
+                acronym: "",
+                pinyinCandidates: []
+            )
+        ]
+        let internalBundleNameFields = document.internalBundleNames.map {
+            Field(
+                kind: .internalBundleName,
+                text: $0,
+                normalized: normalizeField($0),
+                acronym: "",
+                pinyinCandidates: []
+            )
+        }
+        return nameFields + tagFields + noteFields + bundleFields + internalBundleNameFields
+    }
+
+    private static func match(token: String, field: Field) -> TokenMatch? {
+        guard let candidate = bestMatchCandidate(token: token, field: field) else { return nil }
+        let positionBoost = candidate.0 == .exact ? 0 : max(0, 10 - min(candidate.1, 10))
+        let score = field.kind.weight + candidate.0.weight + Double(positionBoost)
+        return TokenMatch(
+            score: score,
+            fieldRank: field.kind.rawValue,
+            fieldKind: field.kind,
+            originalText: field.text
+        )
+    }
+
+    private static func bestMatchCandidate(token: String, field: Field) -> (MatchKind, Int)? {
+        var candidates: [(MatchKind, Int)] = []
+
+        if let textCandidate = matchCandidate(
+            token: token,
+            normalized: field.normalized,
+            options: matchOptions(for: field.kind)
+        ) {
+            candidates.append(textCandidate)
+        }
+        if field.kind == .name && !field.acronym.isEmpty && field.acronym.hasPrefix(token) {
+            candidates.append((.acronym, 0))
+        }
+        for pinyin in field.pinyinCandidates {
+            if let pinyinCandidate = matchPinyinCandidate(token: token, normalized: pinyin) {
+                candidates.append(pinyinCandidate)
+            }
+        }
+
+        return candidates.max { lhs, rhs in
+            if lhs.0.weight != rhs.0.weight { return lhs.0.weight < rhs.0.weight }
+            return lhs.1 > rhs.1
+        }
+    }
+
+    private static func matchOptions(for fieldKind: FieldKind) -> MatchOptions {
+        switch fieldKind {
+        case .name:
+            return MatchOptions(allowSubstring: true, allowFuzzySubsequence: true)
+        case .tag:
+            return MatchOptions(allowSubstring: true, allowFuzzySubsequence: true)
+        case .note:
+            return MatchOptions(allowSubstring: true, allowFuzzySubsequence: false)
+        case .bundleIdentifier, .internalBundleName:
+            return MatchOptions(allowSubstring: false, allowFuzzySubsequence: false)
+        }
+    }
+
+    private static func matchCandidate(
+        token: String,
+        normalized: String,
+        options: MatchOptions
+    ) -> (MatchKind, Int)? {
+        guard !normalized.isEmpty else { return nil }
+        if normalized == token {
+            return (.exact, 0)
+        }
+        if normalized.hasPrefix(token) {
+            return (.prefix, 0)
+        }
+        if options.allowSubstring, let range = normalized.range(of: token) {
+            return (.substring, normalized.distance(from: normalized.startIndex, to: range.lowerBound))
+        }
+        if options.allowFuzzySubsequence, token.count >= 4, isSubsequence(token, of: normalized) {
+            return (.fuzzy, 10)
+        }
+        return nil
+    }
+
+    private static func matchPinyinCandidate(token: String, normalized: String) -> (MatchKind, Int)? {
+        guard !normalized.isEmpty else { return nil }
+        if normalized == token {
+            return (.exact, 0)
+        }
+        if normalized.hasPrefix(token) {
+            return (.prefix, 0)
+        }
+        return nil
+    }
+
+    private static func emptyQueryResults(documents: [QuickSearchDocument], limit: Int) -> [QuickSearchResult] {
+        var used = Set<URL>()
+        let recent = documents
+            .filter { $0.lastOpenedAt != nil }
+            .sorted {
+                if ($0.lastOpenedAt ?? .distantPast) != ($1.lastOpenedAt ?? .distantPast) {
+                    return ($0.lastOpenedAt ?? .distantPast) > ($1.lastOpenedAt ?? .distantPast)
+                }
+                return $0.app.name.localizedStandardCompare($1.app.name) == .orderedAscending
+            }
+
+        let frequent = documents
+            .filter { $0.openCount > 0 }
+            .sorted {
+                if $0.openCount != $1.openCount { return $0.openCount > $1.openCount }
+                return $0.app.name.localizedStandardCompare($1.app.name) == .orderedAscending
+            }
+
+        let ordered = (recent + frequent).filter { used.insert($0.id).inserted }
+        return ordered.prefix(limit).map {
+            QuickSearchResult(
+                document: $0,
+                finalScore: behaviorBoost(for: $0),
+                textScore: 0,
+                bestFieldRank: Int.max,
+                matchedTagName: nil,
+                noteSnippet: nil
+            )
+        }
+    }
+
+    private static func rank(_ lhs: QuickSearchResult, _ rhs: QuickSearchResult) -> Bool {
+        if lhs.finalScore != rhs.finalScore { return lhs.finalScore > rhs.finalScore }
+        if lhs.textScore != rhs.textScore { return lhs.textScore > rhs.textScore }
+        if lhs.bestFieldRank != rhs.bestFieldRank { return lhs.bestFieldRank < rhs.bestFieldRank }
+        let leftDate = lhs.document.lastOpenedAt ?? .distantPast
+        let rightDate = rhs.document.lastOpenedAt ?? .distantPast
+        if leftDate != rightDate { return leftDate > rightDate }
+        if lhs.document.openCount != rhs.document.openCount {
+            return lhs.document.openCount > rhs.document.openCount
+        }
+        if lhs.app.name.count != rhs.app.name.count {
+            return lhs.app.name.count < rhs.app.name.count
+        }
+        return lhs.app.name.localizedStandardCompare(rhs.app.name) == .orderedAscending
+    }
+
+    private static func behaviorBoost(for document: QuickSearchDocument) -> Double {
+        min(recentBoost(for: document.lastOpenedAt) + frequencyBoost(for: document.openCount), 20)
+    }
+
+    private static func recentBoost(for date: Date?) -> Double {
+        guard let date else { return 0 }
+        let age = Date().timeIntervalSince(date)
+        if age <= 24 * 60 * 60 { return 15 }
+        if age <= 7 * 24 * 60 * 60 { return 10 }
+        if age <= 30 * 24 * 60 * 60 { return 5 }
+        return 2
+    }
+
+    private static func frequencyBoost(for openCount: Int) -> Double {
+        min(Double(openCount), 10)
+    }
+
+    private static func normalizeField(_ value: String) -> String {
+        value
+            .folding(options: [.caseInsensitive, .diacriticInsensitive], locale: .current)
+            .lowercased()
+    }
+
+    private static func pinyinCandidates(for value: String) -> [String] {
+        guard value.range(of: #"\p{Han}"#, options: .regularExpression) != nil else { return [] }
+        let mutable = NSMutableString(string: value)
+        CFStringTransform(mutable, nil, kCFStringTransformToLatin, false)
+        CFStringTransform(mutable, nil, kCFStringTransformStripCombiningMarks, false)
+
+        let spaced = normalizeField(mutable as String)
+            .components(separatedBy: CharacterSet.alphanumerics.inverted)
+            .filter { !$0.isEmpty }
+            .joined(separator: " ")
+        guard !spaced.isEmpty else { return [] }
+
+        let compact = spaced.replacingOccurrences(of: " ", with: "")
+        let initials = spaced
+            .split(separator: " ")
+            .compactMap(\.first)
+            .map(String.init)
+            .joined()
+        return uniqueOrdered([spaced, compact, initials].filter { !$0.isEmpty })
+    }
+
+    private static func isSubsequence(_ token: String, of value: String) -> Bool {
+        var searchStart = value.startIndex
+        for character in token {
+            guard let index = value[searchStart...].firstIndex(of: character) else { return false }
+            searchStart = value.index(after: index)
+        }
+        return true
+    }
+
+    private static func acronym(for value: String) -> String {
+        var parts: [Character] = []
+        var nextStartsWord = true
+        var previousWasLowercase = false
+        for character in value {
+            let current = String(character)
+            let isAlphanumeric = current.rangeOfCharacter(from: .alphanumerics) != nil
+            guard isAlphanumeric else {
+                nextStartsWord = true
+                previousWasLowercase = false
+                continue
+            }
+
+            let isUppercase = current.rangeOfCharacter(from: .uppercaseLetters) != nil
+            let isLowercase = current.rangeOfCharacter(from: .lowercaseLetters) != nil
+            if nextStartsWord || (isUppercase && previousWasLowercase) {
+                parts.append(character)
+            }
+            nextStartsWord = false
+            previousWasLowercase = isLowercase
+        }
+        return normalizeField(String(parts))
+    }
+
+    private static func localizedNames(for app: AppInfo) -> [String] {
+        guard let bundle = Bundle(url: app.path) else { return [] }
+        let values = [
+            bundle.localizedInfoDictionary?["CFBundleDisplayName"] as? String,
+            bundle.infoDictionary?["CFBundleDisplayName"] as? String,
+            FileManager.default.displayName(atPath: app.path.path).replacingOccurrences(of: ".app", with: "")
+        ]
+        return uniqueOrdered(values.compactMap { $0 }.compactMap { value in
+            let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
+            return trimmed.isEmpty || trimmed == app.name ? nil : trimmed
+        })
+    }
+
+    private static func internalBundleNames(for app: AppInfo) -> [String] {
+        guard let bundle = Bundle(url: app.path) else { return [] }
+        let values = [
+            bundle.localizedInfoDictionary?["CFBundleName"] as? String,
+            bundle.infoDictionary?["CFBundleName"] as? String
+        ]
+        return uniqueOrdered(values.compactMap { $0 }.compactMap { value in
+            let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
+            return trimmed.isEmpty || trimmed == app.name ? nil : trimmed
+        })
+    }
+
+    private static func snippet(from note: String, token: String) -> String {
+        let trimmed = note.trimmingCharacters(in: .whitespacesAndNewlines)
+        guard trimmed.count > 80 else { return trimmed }
+        return String(trimmed.prefix(77)) + "..."
+    }
+
+    private static func uniqueOrdered(_ values: [String]) -> [String] {
+        var seen = Set<String>()
+        return values.filter { seen.insert(normalizeField($0)).inserted }
+    }
+}
+
+// MARK: - Quick Search UI
+
+enum QuickSearchCommand {
+    case moveUp
+    case moveDown
+    case submit
+    case dismiss
+}
+
+struct QuickSearchOverlayView: View {
+    @Binding var query: String
+    let results: [QuickSearchResult]
+    let selectedID: URL?
+    let focusToken: Int
+    let isLoading: Bool
+    let maxVisibleRows: Int
+    let errorMessage: String?
+    let onCommand: (QuickSearchCommand) -> Void
+    let onHover: (QuickSearchResult) -> Void
+    let onLaunch: (QuickSearchResult) -> Void
+
+    private let panelWidth: CGFloat = 760
+    private let rowHeight: CGFloat = 74
+
+    var body: some View {
+        VStack(alignment: .leading, spacing: 0) {
+            HStack(spacing: 18) {
+                Image(systemName: "magnifyingglass")
+                    .font(.system(size: 29, weight: .regular))
+                    .foregroundStyle(Color.primary.opacity(0.48))
+                    .frame(width: 34)
+
+                QuickSearchTextField(
+                    text: $query,
+                    placeholder: tr("quickSearch.placeholder"),
+                    focusToken: focusToken,
+                    onCommand: onCommand
+                )
+                .frame(height: 44)
+            }
+            .padding(.horizontal, 28)
+            .padding(.top, 22)
+            .padding(.bottom, 18)
+
+            Divider().opacity(0.35)
+
+            if isLoading {
+                HStack(spacing: 10) {
+                    ProgressView()
+                        .controlSize(.small)
+                    Text(tr("quickSearch.loading"))
+                        .font(.system(size: 15, weight: .medium))
+                        .foregroundStyle(.secondary)
+                    Spacer(minLength: 0)
+                }
+                .padding(.horizontal, 28)
+                .padding(.vertical, 24)
+                .frame(minHeight: 86)
+            } else if let errorMessage {
+                QuickSearchMessageRow(
+                    systemImage: "exclamationmark.triangle.fill",
+                    message: errorMessage,
+                    tint: .orange
+                )
+            } else if results.isEmpty {
+                QuickSearchMessageRow(
+                    systemImage: query.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? "keyboard" : "magnifyingglass",
+                    message: query.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
+                        ? tr("quickSearch.emptyPrompt")
+                        : tr("quickSearch.noResults"),
+                    tint: .secondary
+                )
+            } else {
+                ScrollViewReader { scrollProxy in
+                    ScrollView(.vertical, showsIndicators: results.count > maxVisibleRows) {
+                        LazyVStack(spacing: 2) {
+                            ForEach(results) { result in
+                                QuickSearchResultRow(
+                                    result: result,
+                                    isSelected: result.id == selectedID
+                                )
+                                .frame(height: rowHeight)
+                                .id(result.id)
+                                .contentShape(Rectangle())
+                                .onHover { hovering in
+                                    if hovering { onHover(result) }
+                                }
+                                .onTapGesture {
+                                    onLaunch(result)
+                                }
+                            }
+                        }
+                        .padding(.horizontal, 10)
+                        .padding(.vertical, 10)
+                    }
+                    .frame(height: CGFloat(min(results.count, maxVisibleRows)) * (rowHeight + 2) + 20)
+                    .onChange(of: selectedID) { _, id in
+                        guard let id else { return }
+                        withAnimation(.easeOut(duration: 0.08)) {
+                            scrollProxy.scrollTo(id, anchor: .center)
+                        }
+                    }
+                }
+            }
+        }
+        .frame(width: panelWidth)
+        .background(
+            RoundedRectangle(cornerRadius: 34, style: .continuous)
+                .fill(.regularMaterial)
+                .shadow(color: .black.opacity(0.18), radius: 36, y: 18)
+        )
+        .overlay(
+            RoundedRectangle(cornerRadius: 34, style: .continuous)
+                .stroke(Color.primary.opacity(0.10), lineWidth: 1)
+        )
+        .accessibilityElement(children: .contain)
+        .accessibilityLabel(tr("quickSearch.title"))
+    }
+}
+
+private struct QuickSearchResultRow: View {
+    let result: QuickSearchResult
+    let isSelected: Bool
+    @Environment(\.colorScheme) private var colorScheme
+
+    var body: some View {
+        HStack(spacing: 16) {
+            Image(nsImage: result.app.icon)
+                .resizable()
+                .frame(width: 46, height: 46)
+                .cornerRadius(10)
+
+            VStack(alignment: .leading, spacing: 4) {
+                Text(result.app.name)
+                    .font(.system(size: 20, weight: .semibold))
+                    .foregroundStyle(.primary)
+                    .lineLimit(1)
+                    .truncationMode(.tail)
+
+                if let detailText {
+                    Text(detailText)
+                        .font(.system(size: 16, weight: .medium))
+                        .foregroundStyle(Color.primary.opacity(0.38))
+                        .lineLimit(1)
+                        .truncationMode(.tail)
+                }
+            }
+            .layoutPriority(1)
+
+            Spacer(minLength: 8)
+
+            if let tagName = rightTagName {
+                Text(tagName)
+                    .font(.system(size: 14, weight: .semibold))
+                    .foregroundStyle(Color.primary.opacity(0.46))
+                    .lineLimit(1)
+                    .truncationMode(.tail)
+                    .padding(.horizontal, 12)
+                    .frame(height: 32)
+                    .frame(maxWidth: 128)
+                    .background(
+                        Capsule(style: .continuous)
+                            .fill(Color.primary.opacity(colorScheme == .dark ? 0.12 : 0.07))
+                    )
+            }
+        }
+        .padding(.horizontal, 18)
+        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
+        .background(
+            RoundedRectangle(cornerRadius: 18, style: .continuous)
+                .fill(isSelected ? selectedFill : Color.clear)
+        )
+        .accessibilityLabel(accessibilityText)
+    }
+
+    private var selectedFill: Color {
+        colorScheme == .dark ? Color.white.opacity(0.14) : Color.black.opacity(0.075)
+    }
+
+    private var detailText: String? {
+        if let note = result.noteSnippet, !note.isEmpty {
+            return note
+        }
+        let note = result.document.note.trimmingCharacters(in: .whitespacesAndNewlines)
+        if !note.isEmpty {
+            return note.count > 72 ? String(note.prefix(69)) + "..." : note
+        }
+        return nil
+    }
+
+    private var rightTagName: String? {
+        let tag = result.matchedTagName ?? result.document.tagNames.first
+        guard let tag, !tag.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil }
+        return tag
+    }
+
+    private var accessibilityText: String {
+        [result.app.name, detailText].compactMap { $0 }.joined(separator: ", ")
+    }
+}
+
+private struct QuickSearchMessageRow: View {
+    let systemImage: String
+    let message: String
+    let tint: Color
+
+    var body: some View {
+        HStack(spacing: 10) {
+            Image(systemName: systemImage)
+                .font(.system(size: 20, weight: .regular))
+                .foregroundStyle(tint)
+                .frame(width: 28)
+            Text(message)
+                .font(.system(size: 15, weight: .medium))
+                .foregroundStyle(.secondary)
+                .lineLimit(2)
+                .fixedSize(horizontal: false, vertical: true)
+            Spacer(minLength: 0)
+        }
+        .padding(.horizontal, 28)
+        .padding(.vertical, 24)
+        .frame(minHeight: 86)
+        .accessibilityLabel(message)
+    }
+}
+
+private struct QuickSearchTextField: NSViewRepresentable {
+    @Binding var text: String
+    let placeholder: String
+    let focusToken: Int
+    let onCommand: (QuickSearchCommand) -> Void
+
+    func makeNSView(context: Context) -> QuickSearchNativeTextField {
+        let field = QuickSearchNativeTextField()
+        field.isBordered = false
+        field.isBezeled = false
+        field.drawsBackground = false
+        field.focusRingType = .none
+        field.font = NSFont.systemFont(ofSize: 28, weight: .regular)
+        field.placeholderString = placeholder
+        field.delegate = context.coordinator
+        field.onCommand = onCommand
+        field.setAccessibilityLabel(tr("quickSearch.inputAccessibility"))
+        context.coordinator.field = field
+        DispatchQueue.main.async {
+            field.window?.makeFirstResponder(field)
+        }
+        return field
+    }
+
+    func updateNSView(_ field: QuickSearchNativeTextField, context: Context) {
+        if field.stringValue != text {
+            field.stringValue = text
+        }
+        field.placeholderString = placeholder
+        field.onCommand = onCommand
+        if context.coordinator.lastFocusToken != focusToken {
+            context.coordinator.lastFocusToken = focusToken
+            DispatchQueue.main.async {
+                field.window?.makeFirstResponder(field)
+            }
+        }
+    }
+
+    func makeCoordinator() -> Coordinator {
+        Coordinator(text: $text)
+    }
+
+    final class Coordinator: NSObject, NSTextFieldDelegate {
+        var text: Binding<String>
+        var lastFocusToken = 0
+        weak var field: NSTextField?
+
+        init(text: Binding<String>) {
+            self.text = text
+        }
+
+        func controlTextDidChange(_ obj: Notification) {
+            guard let field = obj.object as? NSTextField else { return }
+            text.wrappedValue = field.stringValue
+        }
+    }
+}
+
+private final class QuickSearchNativeTextField: NSTextField {
+    var onCommand: ((QuickSearchCommand) -> Void)?
+
+    override func keyDown(with event: NSEvent) {
+        switch Int(event.keyCode) {
+        case kVK_UpArrow:
+            onCommand?(.moveUp)
+        case kVK_DownArrow:
+            onCommand?(.moveDown)
+        case kVK_Return:
+            onCommand?(.submit)
+        case kVK_Escape:
+            onCommand?(.dismiss)
+        default:
+            super.keyDown(with: event)
+        }
+    }
+}
+
+struct QuickSearchBackdropClickView: NSViewRepresentable {
+    let onClick: () -> Void
+
+    func makeNSView(context: Context) -> QuickSearchBackdropNSView {
+        let view = QuickSearchBackdropNSView()
+        view.onClick = onClick
+        return view
+    }
+
+    func updateNSView(_ view: QuickSearchBackdropNSView, context: Context) {
+        view.onClick = onClick
+    }
+}
+
+final class QuickSearchBackdropNSView: NSView {
+    var onClick: (() -> Void)?
+
+    override func hitTest(_ point: NSPoint) -> NSView? {
+        bounds.contains(point) ? self : nil
+    }
+
+    override func mouseDown(with event: NSEvent) {
+        onClick?()
+    }
+}
+
+// MARK: - Hotkey Capture UI
+
+struct HotkeyCaptureView: NSViewRepresentable {
+    let isActive: Bool
+    let onCapture: (LauncherHotkey) -> Void
+    let onCancel: () -> Void
+
+    func makeNSView(context: Context) -> HotkeyCaptureNSView {
+        let view = HotkeyCaptureNSView()
+        view.onCapture = onCapture
+        view.onCancel = onCancel
+        return view
+    }
+
+    func updateNSView(_ view: HotkeyCaptureNSView, context: Context) {
+        view.onCapture = onCapture
+        view.onCancel = onCancel
+        view.setActive(isActive)
+    }
+}
+
+final class HotkeyCaptureNSView: NSView {
+    var onCapture: ((LauncherHotkey) -> Void)?
+    var onCancel: (() -> Void)?
+    private var keyMonitor: Any?
+
+    override var acceptsFirstResponder: Bool { true }
+
+    deinit {
+        removeKeyMonitor()
+    }
+
+    func setActive(_ active: Bool) {
+        if active {
+            installKeyMonitorIfNeeded()
+            DispatchQueue.main.async { [weak self] in
+                guard let self else { return }
+                self.window?.makeFirstResponder(self)
+            }
+        } else {
+            removeKeyMonitor()
+        }
+    }
+
+    override func keyDown(with event: NSEvent) {
+        handle(event)
+    }
+
+    private func installKeyMonitorIfNeeded() {
+        guard keyMonitor == nil else { return }
+        keyMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
+            guard let self else { return event }
+            self.handle(event)
+            return nil
+        }
+    }
+
+    private func removeKeyMonitor() {
+        if let keyMonitor {
+            NSEvent.removeMonitor(keyMonitor)
+            self.keyMonitor = nil
+        }
+    }
+
+    private func handle(_ event: NSEvent) {
+        if event.keyCode == UInt16(kVK_Escape) {
+            onCancel?()
+            return
+        }
+        if let hotkey = LauncherHotkey.from(event: event) {
+            onCapture?(hotkey)
+        } else {
+            NSSound.beep()
+        }
+    }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15fcbe7..182cf6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
 # Apptag Changelog
 
+## [7.5.1] — 2026-05-19
+
+- 设置页新增独立「快捷键」页签,将主界面快捷键与 Quick Search 直接快捷键管理从「通用」页拆出
+- 移除设置页中与当前快捷键设置重复的静态按键帽提示,避免「关于」等页面继续展示旧快捷键视觉元素
+- 按 C 版规则收窄「快捷搜索」匹配:短查询不再放大无关结果,备注恢复拼音前缀匹配,Tag 支持原文非连续字符匹配,Bundle ID 与内部 Bundle 名仅支持精确/前缀命中
+- 版本号更新为 `7.5.1`,Build 更新为 `751`
+
+## [7.5.0] — 2026-05-19
+
+- 新增 Quick Search:在 App list 中按 `Space` 打开快速搜索浮层,支持按 App 名称、本地化名称、标签、备注和 Bundle ID 本地搜索
+- Quick Search 支持精确、前缀、子串、首字母缩写、非连续字符、中文直接匹配和本地中文拼音候选匹配
+- 空查询显示最近/常用 App 建议,支持键盘上下选择、回车启动、鼠标悬停选择和点击启动
+- 新增直接打开 Quick Search 的可配置全局快捷键,默认关闭,并支持快捷键录制、清除、恢复默认、重试注册和冲突状态提示
+- 快捷键冲突状态区分 `Active` / `Conflict` / `Disabled`,已知 macOS 默认快捷键显示专用说明,注册失败时保留旧快捷键可用
+- Quick Search 使用 macOS Spotlight 风格玻璃面板,支持外部点击关闭、Esc 两级退出、结果滚动和稳定顶部定位
+- 启动历史增加最近成功启动时间,用于 Quick Search 空查询建议排序;启动失败不更新历史
+- 所有 Quick Search 用户可见文案接入本地化资源
+- 版本号更新为 `7.5.0`,Build 更新为 `750`
+
 ## [7.3.5] — 2026-05-18
 
 - 为菜单栏图标设置稳定 `NSStatusItem.autosaveName`,让 macOS 与 Thaw 更容易识别为同一个菜单栏项

--
Gitblit v1.9.3