diff --git a/Marlin/src/HAL/HAL_LPC1768/main.cpp b/Marlin/src/HAL/HAL_LPC1768/main.cpp
index ab5b184b475..b20841bdeb9 100644
--- a/Marlin/src/HAL/HAL_LPC1768/main.cpp
+++ b/Marlin/src/HAL/HAL_LPC1768/main.cpp
@@ -155,7 +155,7 @@ void HAL_idletask() {
     // a PC via USB.
     // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but
     // this will not reliably detect delete operations. To be safe we will lock
-    // the disk if Marlin has it mounted. Unfortuately there is currently no way
+    // the disk if Marlin has it mounted. Unfortunately there is currently no way
     // to unmount the disk from the LCD menu.
     // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN())
     if (card.isMounted())
diff --git a/Marlin/src/HAL/HAL_STM32F1/HAL.cpp b/Marlin/src/HAL/HAL_STM32F1/HAL.cpp
index e1f2e21ffd7..802a4891010 100644
--- a/Marlin/src/HAL/HAL_STM32F1/HAL.cpp
+++ b/Marlin/src/HAL/HAL_STM32F1/HAL.cpp
@@ -233,7 +233,7 @@ void HAL_idletask() {
       // a PC via USB.
       // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but
       // this will not reliably detect delete operations. To be safe we will lock
-      // the disk if Marlin has it mounted. Unfortuately there is currently no way
+      // the disk if Marlin has it mounted. Unfortunately there is currently no way
       // to unmount the disk from the LCD menu.
       // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN())
       /* copy from lpc1768 framework, should be fixed later for process SHARED_SD_CARD*/
diff --git a/Marlin/src/Marlin.cpp b/Marlin/src/Marlin.cpp
index 07970b72fce..5e734795e92 100644
--- a/Marlin/src/Marlin.cpp
+++ b/Marlin/src/Marlin.cpp
@@ -173,10 +173,6 @@
   #include "feature/prusa_MMU2/mmu2.h"
 #endif
 
-#if ENABLED(EXTENSIBLE_UI)
-  #include "lcd/extensible_ui/ui_api.h"
-#endif
-
 #if HAS_DRIVER(L6470)
   #include "libs/L6470/L6470_Marlin.h"
 #endif
@@ -330,71 +326,6 @@ void disable_all_steppers() {
   disable_e_steppers();
 }
 
-#if HAS_FILAMENT_SENSOR
-
-  void event_filament_runout() {
-
-    #if ENABLED(ADVANCED_PAUSE_FEATURE)
-      if (did_pause_print) return;  // Action already in progress. Purge triggered repeated runout.
-    #endif
-
-    #if ENABLED(EXTENSIBLE_UI)
-      ExtUI::onFilamentRunout(ExtUI::getActiveTool());
-    #endif
-
-    #if EITHER(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS)
-      const char tool = '0'
-        #if NUM_RUNOUT_SENSORS > 1
-          + active_extruder
-        #endif
-      ;
-    #endif
-
-    //action:out_of_filament
-    #if ENABLED(HOST_PROMPT_SUPPORT)
-      host_prompt_reason = PROMPT_FILAMENT_RUNOUT;
-      host_action_prompt_end();
-      host_action_prompt_begin(PSTR("FilamentRunout T"), false);
-      SERIAL_CHAR(tool);
-      SERIAL_EOL();
-      host_action_prompt_show();
-    #endif
-
-    const bool run_runout_script = !runout.host_handling;
-
-    #if ENABLED(HOST_ACTION_COMMANDS)
-      if (run_runout_script
-        && ( strstr(FILAMENT_RUNOUT_SCRIPT, "M600")
-          || strstr(FILAMENT_RUNOUT_SCRIPT, "M125")
-          #if ENABLED(ADVANCED_PAUSE_FEATURE)
-            || strstr(FILAMENT_RUNOUT_SCRIPT, "M25")
-          #endif
-        )
-      ) {
-        host_action_paused(false);
-      }
-      else {
-        // Legacy Repetier command for use until newer version supports standard dialog
-        // To be removed later when pause command also triggers dialog
-        #ifdef ACTION_ON_FILAMENT_RUNOUT
-          host_action(PSTR(ACTION_ON_FILAMENT_RUNOUT " T"), false);
-          SERIAL_CHAR(tool);
-          SERIAL_EOL();
-        #endif
-
-        host_action_pause(false);
-      }
-      SERIAL_ECHOPGM(" " ACTION_REASON_ON_FILAMENT_RUNOUT " ");
-      SERIAL_CHAR(tool);
-      SERIAL_EOL();
-    #endif // HOST_ACTION_COMMANDS
-
-    if (run_runout_script)
-      queue.inject_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
-  }
-
-#endif // HAS_FILAMENT_SENSOR
-
 #if ENABLED(G29_RETRY_AND_RECOVER)
 
   void event_probe_failure() {
diff --git a/Marlin/src/Marlin.h b/Marlin/src/Marlin.h
index 37f43768f1b..8b64c9a2cb8 100644
--- a/Marlin/src/Marlin.h
+++ b/Marlin/src/Marlin.h
@@ -371,10 +371,6 @@ void protected_pin_err();
   inline void suicide() { OUT_WRITE(SUICIDE_PIN, LOW); }
 #endif
 
-#if HAS_FILAMENT_SENSOR
-  void event_filament_runout();
-#endif
-
 #if ENABLED(G29_RETRY_AND_RECOVER)
   void event_probe_recover();
   void event_probe_failure();
diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp
index a4172fc0860..6b8905c3b99 100644
--- a/Marlin/src/feature/runout.cpp
+++ b/Marlin/src/feature/runout.cpp
@@ -58,4 +58,79 @@ void FilamentSensorBase::filament_present(const uint8_t extruder) {
   int8_t RunoutResponseDebounced::runout_count; // = 0
 #endif
 
+//
+// Filament Runout event handler
+//
+#include "../Marlin.h"
+#include "../gcode/queue.h"
+
+#if ENABLED(HOST_ACTION_COMMANDS)
+  #include "host_actions.h"
+#endif
+
+#if ENABLED(EXTENSIBLE_UI)
+  #include "../lcd/extensible_ui/ui_api.h"
+#endif
+
+void event_filament_runout() {
+
+  #if ENABLED(ADVANCED_PAUSE_FEATURE)
+    if (did_pause_print) return;  // Action already in progress. Purge triggered repeated runout.
+  #endif
+
+  #if ENABLED(EXTENSIBLE_UI)
+    ExtUI::onFilamentRunout(ExtUI::getActiveTool());
+  #endif
+
+  #if EITHER(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS)
+    const char tool = '0'
+      #if NUM_RUNOUT_SENSORS > 1
+        + active_extruder
+      #endif
+    ;
+  #endif
+
+  //action:out_of_filament
+  #if ENABLED(HOST_PROMPT_SUPPORT)
+    host_prompt_reason = PROMPT_FILAMENT_RUNOUT;
+    host_action_prompt_end();
+    host_action_prompt_begin(PSTR("FilamentRunout T"), false);
+    SERIAL_CHAR(tool);
+    SERIAL_EOL();
+    host_action_prompt_show();
+  #endif
+
+  const bool run_runout_script = !runout.host_handling;
+
+  #if ENABLED(HOST_ACTION_COMMANDS)
+    if (run_runout_script
+      && ( strstr(FILAMENT_RUNOUT_SCRIPT, "M600")
+        || strstr(FILAMENT_RUNOUT_SCRIPT, "M125")
+        #if ENABLED(ADVANCED_PAUSE_FEATURE)
+          || strstr(FILAMENT_RUNOUT_SCRIPT, "M25")
+        #endif
+      )
+    ) {
+      host_action_paused(false);
+    }
+    else {
+      // Legacy Repetier command for use until newer version supports standard dialog
+      // To be removed later when pause command also triggers dialog
+      #ifdef ACTION_ON_FILAMENT_RUNOUT
+        host_action(PSTR(ACTION_ON_FILAMENT_RUNOUT " T"), false);
+        SERIAL_CHAR(tool);
+        SERIAL_EOL();
+      #endif
+
+      host_action_pause(false);
+    }
+    SERIAL_ECHOPGM(" " ACTION_REASON_ON_FILAMENT_RUNOUT " ");
+    SERIAL_CHAR(tool);
+    SERIAL_EOL();
+  #endif // HOST_ACTION_COMMANDS
+
+  if (run_runout_script)
+    queue.inject_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
+}
+
 #endif // HAS_FILAMENT_SENSOR
diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h
index af8ea1faef7..4fed18e359f 100644
--- a/Marlin/src/feature/runout.h
+++ b/Marlin/src/feature/runout.h
@@ -46,6 +46,8 @@
   #define FILAMENT_RUNOUT_THRESHOLD 5
 #endif
 
+void event_filament_runout();
+
 class FilamentMonitorBase {
   public:
     static bool enabled, filament_ran_out;
diff --git a/Marlin/src/gcode/feature/pause/M701_M702.cpp b/Marlin/src/gcode/feature/pause/M701_M702.cpp
index 80a7f76d934..b4bab7e86a2 100644
--- a/Marlin/src/gcode/feature/pause/M701_M702.cpp
+++ b/Marlin/src/gcode/feature/pause/M701_M702.cpp
@@ -102,15 +102,20 @@ void GcodeSuite::M701() {
   #if ENABLED(PRUSA_MMU2)
     mmu2.load_filament_to_nozzle(target_extruder);
   #else
-    constexpr float slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
-    const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
-                                                        : fc_settings[active_extruder].load_length);
-    load_filament(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS,
-                  true, thermalManager.still_heating(target_extruder), PAUSE_MODE_LOAD_FILAMENT
-                  #if ENABLED(DUAL_X_CARRIAGE)
-                    , target_extruder
-                  #endif
-                );
+    constexpr float     purge_length = ADVANCED_PAUSE_PURGE_LENGTH,
+                    slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
+        const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
+                                                            : fc_settings[active_extruder].load_length);
+    load_filament(
+      slow_load_length, fast_load_length, purge_length,
+      FILAMENT_CHANGE_ALERT_BEEPS,
+      true,                                           // show_lcd
+      thermalManager.still_heating(target_extruder),  // pause_for_user
+      PAUSE_MODE_LOAD_FILAMENT                        // pause_mode
+      #if ENABLED(DUAL_X_CARRIAGE)
+        , target_extruder                             // Dual X target
+      #endif
+    );
   #endif
 
   // Restore Z axis