diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs
--- a/crates/ui-egui/src/menus.rs
+++ b/crates/ui-egui/src/menus.rs
@@ -180,9 +180,25 @@ pub fn targets_source(app: &FilmcraftApp, params: &Value) -> bool {
     }
 }
 
+/// Edit ▸ Select All while a text field has the keyboard (the Project panel's search, a name being
+/// typed) selects that field's text, not the timeline clips: on macOS the native menu takes Cmd+A
+/// before the field sees the key. The selection is set on the field's state, so it holds however
+/// late in the pass the command runs (menu inbox or control channel); the field clamps the end to
+/// its text. False when no text field has the keyboard.
+fn select_all_in_text_field(ctx: &egui::Context) -> bool {
+    use egui::text::{CCursor, CCursorRange};
+    let Some(id) = ctx.memory(|m| m.focused()) else { return false };
+    let Some(mut state) = egui::TextEdit::load_state(ctx, id) else { return false };
+    state.cursor.set_char_range(Some(CCursorRange::two(CCursor::new(0), CCursor::new(usize::MAX))));
+    state.store(ctx, id);
+    true
+}
+
 /// Execute a UI or engine command by id.
 pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params: Value) -> Result<Value, String> {
-    if id == "edit.selectAll" && (crate::panels::graphics::select_all_edited_text(app) || crate::panels::effect_controls::select_all_keyframes(app)) {
+    if id == "edit.selectAll"
+        && (select_all_in_text_field(ctx) || crate::panels::graphics::select_all_edited_text(app) || crate::panels::effect_controls::select_all_keyframes(app))
+    {
         return Ok(Value::Null);
     }
     if filmcraft_engine::source_monitor::source_command(id) && targets_source(app, &params) && params.get("target").is_none() {
diff --git a/crates/ui-egui/tests/it/project_panel_ui.rs b/crates/ui-egui/tests/it/project_panel_ui.rs
--- a/crates/ui-egui/tests/it/project_panel_ui.rs
+++ b/crates/ui-egui/tests/it/project_panel_ui.rs
@@ -554,6 +554,34 @@ fn select_all_takes_only_the_shown_bin() {
     assert_eq!(sorted(&d.app().session.state.project_selection), footage);
 }
 
+/// Select All while typing in the Project panel's search selects the typed text, not the clips: on
+/// macOS the native menu takes Cmd+A before the field sees the key and sent Edit ▸ Select All,
+/// which selected every clip on the timeline. Typing after it replaces the search.
+#[test]
+fn select_all_in_the_search_box_selects_its_text() {
+    let mut d = project_driver();
+    d.click("project.search");
+    d.ok("ui.type", json!({"text": "comedy manager"}));
+    d.frames(2);
+    let (timeline, items) = (d.app().session.state.selection.clone(), d.app().session.state.project_selection.clone());
+    let (tx, rx) = channel();
+    d.app().command_inbox = Some(rx);
+    tx.send("edit.selectAll".to_string()).unwrap();
+    d.frames(2);
+    assert_eq!(d.app().session.state.selection, timeline, "the timeline selection is left alone");
+    assert_eq!(d.app().session.state.project_selection, items, "and so are the Project panel's items");
+    d.ok("ui.type", json!({"text": "club"}));
+    d.frames(2);
+    assert_eq!(d.app().ui.project_search, "club", "the typed text replaced the selected search");
+    // the same from the control channel, which runs after the field has been laid out
+    d.ok("ui.menu.invoke", json!({"id": "edit.selectAll"}));
+    d.frames(2);
+    assert_eq!(d.app().session.state.selection, timeline);
+    d.ok("ui.type", json!({"text": "stool"}));
+    d.frames(2);
+    assert_eq!(d.app().ui.project_search, "stool");
+}
+
 #[test]
 fn a_dragged_bin_nests_in_another_and_back_out() {
     // #456: a bin stayed wherever it was created; dragging it onto another bin did nothing
