diff --git a/solitaire_engine/src/home_plugin.rs b/solitaire_engine/src/home_plugin.rs index dd22975..7cc0c36 100644 --- a/solitaire_engine/src/home_plugin.rs +++ b/solitaire_engine/src/home_plugin.rs @@ -475,13 +475,19 @@ fn handle_home_cancel_button( keys: Option>>, cancel_buttons: Query<&Interaction, (With, Changed)>, screens: Query>, + other_modal_scrims: Query<(), (With, Without)>, ) { if screens.is_empty() { return; } let click = cancel_buttons.iter().any(|i| *i == Interaction::Pressed); let esc = keys.is_some_and(|k| k.just_pressed(KeyCode::Escape)); - if !click && !esc { + // Esc only closes Home when it is the *topmost* modal. With Profile + // (or any other ModalScrim) layered on top, the topmost owns the + // dismissal — without this gate a single Esc closed the back + // modal (Home) and left the front modal orphaned. + let esc_targets_home = esc && other_modal_scrims.is_empty(); + if !click && !esc_targets_home { return; } for entity in &screens { diff --git a/solitaire_engine/src/profile_plugin.rs b/solitaire_engine/src/profile_plugin.rs index 9d0d7de..c41348c 100644 --- a/solitaire_engine/src/profile_plugin.rs +++ b/solitaire_engine/src/profile_plugin.rs @@ -146,7 +146,17 @@ fn toggle_profile_screen( screens: Query>, ) { let button_clicked = requests.read().count() > 0; - if !keys.just_pressed(KeyCode::KeyP) && !button_clicked { + let p_pressed = keys.just_pressed(KeyCode::KeyP); + let esc_pressed = keys.just_pressed(KeyCode::Escape); + let already_open = !screens.is_empty(); + // P / button toggles open-or-close. Esc only ever closes — when + // Profile is layered over Home (clicking the new Home stats chip + // opens this on top), Esc must dismiss the *topmost* modal. + // Without this branch, Esc fell through to Home's cancel handler + // and closed the wrong modal. + let want_open = !already_open && (p_pressed || button_clicked); + let want_close = already_open && (p_pressed || button_clicked || esc_pressed); + if !want_open && !want_close { return; } if let Ok(entity) = screens.single() {