diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp
index f970c46a67..8206dc319f 100644
--- a/Marlin/src/core/utility.cpp
+++ b/Marlin/src/core/utility.cpp
@@ -333,7 +333,7 @@ void safe_delay(millis_t ms) {
       #elif ENABLED(AUTO_BED_LEVELING_UBL)
         SERIAL_ECHOPGM("UBL");
       #endif
-      if (leveling_is_active()) {
+      if (planner.leveling_active) {
         SERIAL_ECHOLNPGM(" (enabled)");
         #if ABL_PLANAR
           const float diff[XYZ] = {
@@ -364,7 +364,7 @@ void safe_delay(millis_t ms) {
     #elif ENABLED(MESH_BED_LEVELING)
 
       SERIAL_ECHOPGM("Mesh Bed Leveling");
-      if (leveling_is_active()) {
+      if (planner.leveling_active) {
         float lz = current_position[Z_AXIS];
         planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], lz);
         SERIAL_ECHOLNPGM(" (enabled)");
diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp
index 8d944e0364..d91056bfc1 100644
--- a/Marlin/src/feature/bedlevel/bedlevel.cpp
+++ b/Marlin/src/feature/bedlevel/bedlevel.cpp
@@ -44,7 +44,7 @@
 bool leveling_is_valid() {
   return
     #if ENABLED(MESH_BED_LEVELING)
-      mbl.has_mesh()
+      mbl.has_mesh
     #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
       !!bilinear_grid_spacing[X_AXIS]
     #elif ENABLED(AUTO_BED_LEVELING_UBL)
@@ -55,18 +55,6 @@ bool leveling_is_valid() {
   ;
 }
 
-bool leveling_is_active() {
-  return
-    #if ENABLED(MESH_BED_LEVELING)
-      mbl.active()
-    #elif ENABLED(AUTO_BED_LEVELING_UBL)
-      ubl.state.active
-    #else // OLDSCHOOL_ABL
-      planner.abl_enabled
-    #endif
-  ;
-}
-
 /**
  * Turn bed leveling on or off, fixing the current
  * position as-needed.
@@ -82,7 +70,7 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
     constexpr bool can_change = true;
   #endif
 
-  if (can_change && enable != leveling_is_active()) {
+  if (can_change && enable != planner.leveling_active) {
 
     #if ENABLED(MESH_BED_LEVELING)
 
@@ -90,23 +78,23 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
         planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
 
       const bool enabling = enable && leveling_is_valid();
-      mbl.set_active(enabling);
+      planner.leveling_active = enabling;
       if (enabling) planner.unapply_leveling(current_position);
 
     #elif ENABLED(AUTO_BED_LEVELING_UBL)
       #if PLANNER_LEVELING
-        if (ubl.state.active) {                       // leveling from on to off
+        if (planner.leveling_active) {                   // leveling from on to off
           // change unleveled current_position to physical current_position without moving steppers.
           planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-          ubl.state.active = false;                   // disable only AFTER calling apply_leveling
+          planner.leveling_active = false;                   // disable only AFTER calling apply_leveling
         }
         else {                                        // leveling from off to on
-          ubl.state.active = true;                    // enable BEFORE calling unapply_leveling, otherwise ignored
+          planner.leveling_active = true;                    // enable BEFORE calling unapply_leveling, otherwise ignored
           // change physical current_position to unleveled current_position without moving steppers.
           planner.unapply_leveling(current_position);
         }
       #else
-        ubl.state.active = enable;                    // just flip the bit, current_position will be wrong until next move.
+        planner.leveling_active = enable;                    // just flip the bit, current_position will be wrong until next move.
       #endif
 
     #else // OLDSCHOOL_ABL
@@ -118,7 +106,7 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
       #endif
 
       // Enable or disable leveling compensation in the planner
-      planner.abl_enabled = enable;
+      planner.leveling_active = enable;
 
       if (!enable)
         // When disabling just get the current position from the steppers.
@@ -143,23 +131,18 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
 
   void set_z_fade_height(const float zfh) {
 
-    const bool level_active = leveling_is_active();
+    const bool level_active = planner.leveling_active;
 
     #if ENABLED(AUTO_BED_LEVELING_UBL)
+      if (level_active) set_bed_leveling_enabled(false);  // turn off before changing fade height for proper apply/unapply leveling to maintain current_position
+    #endif
 
-      if (level_active)
-        set_bed_leveling_enabled(false);  // turn off before changing fade height for proper apply/unapply leveling to maintain current_position
-      planner.z_fade_height = zfh;
-      planner.inverse_z_fade_height = RECIPROCAL(zfh);
-      if (level_active)
+    planner.set_z_fade_height(zfh);
+
+    if (level_active) {
+      #if ENABLED(AUTO_BED_LEVELING_UBL)
         set_bed_leveling_enabled(true);  // turn back on after changing fade height
-
-    #else
-
-      planner.z_fade_height = zfh;
-      planner.inverse_z_fade_height = RECIPROCAL(zfh);
-
-      if (level_active) {
+      #else
         set_current_from_steppers_for_axis(
           #if ABL_PLANAR
             ALL_AXES
@@ -167,8 +150,8 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) {
             Z_AXIS
           #endif
         );
-      }
-    #endif
+      #endif
+    }
   }
 
 #endif // ENABLE_LEVELING_FADE_HEIGHT
@@ -181,7 +164,7 @@ void reset_bed_level() {
   #if ENABLED(MESH_BED_LEVELING)
     if (leveling_is_valid()) {
       mbl.reset();
-      mbl.set_has_mesh(false);
+      mbl.has_mesh = false;
     }
   #else
     #if ENABLED(DEBUG_LEVELING_FEATURE)
diff --git a/Marlin/src/feature/bedlevel/bedlevel.h b/Marlin/src/feature/bedlevel/bedlevel.h
index 31c444cf15..ecd2297032 100644
--- a/Marlin/src/feature/bedlevel/bedlevel.h
+++ b/Marlin/src/feature/bedlevel/bedlevel.h
@@ -40,7 +40,6 @@
 #endif
 
 bool leveling_is_valid();
-bool leveling_is_active();
 void set_bed_leveling_enabled(const bool enable=true);
 void reset_bed_level();
 
diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp
index dd5d1423c3..d0678e7514 100644
--- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp
+++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp
@@ -31,7 +31,7 @@
 
   mesh_bed_leveling mbl;
 
-  uint8_t mesh_bed_leveling::status;
+  bool mesh_bed_leveling::has_mesh;
 
   float mesh_bed_leveling::z_offset,
         mesh_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
@@ -47,7 +47,7 @@
   }
 
   void mesh_bed_leveling::reset() {
-    status = MBL_STATUS_NONE;
+    has_mesh = false;
     z_offset = 0;
     ZERO(z_values);
   }
diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h
index c9ff901ede..034328713c 100644
--- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h
+++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h
@@ -34,18 +34,12 @@ enum MeshLevelingState {
   MeshReset
 };
 
-enum MBLStatus {
-  MBL_STATUS_NONE = 0,
-  MBL_STATUS_HAS_MESH_BIT = 0,
-  MBL_STATUS_ACTIVE_BIT = 1
-};
-
 #define MESH_X_DIST ((MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_POINTS_X - 1))
 #define MESH_Y_DIST ((MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_POINTS_Y - 1))
 
 class mesh_bed_leveling {
 public:
-  static uint8_t status; // Has Mesh and Is Active bits
+  static bool has_mesh;
   static float z_offset,
                z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
                index_to_xpos[GRID_MAX_POINTS_X],
@@ -57,11 +51,6 @@ public:
 
   static void set_z(const int8_t px, const int8_t py, const float &z) { z_values[px][py] = z; }
 
-  static bool active()                       { return TEST(status, MBL_STATUS_ACTIVE_BIT); }
-  static void set_active(const bool onOff)   { onOff ? SBI(status, MBL_STATUS_ACTIVE_BIT) : CBI(status, MBL_STATUS_ACTIVE_BIT); }
-  static bool has_mesh()                     { return TEST(status, MBL_STATUS_HAS_MESH_BIT); }
-  static void set_has_mesh(const bool onOff) { onOff ? SBI(status, MBL_STATUS_HAS_MESH_BIT) : CBI(status, MBL_STATUS_HAS_MESH_BIT); }
-
   static inline void zigzag(const int8_t index, int8_t &px, int8_t &py) {
     px = index % (GRID_MAX_POINTS_X);
     py = index / (GRID_MAX_POINTS_X);
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp
index 4ebd832383..ff7d2e72dd 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp
@@ -51,7 +51,7 @@
   void unified_bed_leveling::report_state() {
     echo_name();
     SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " ");
-    if (!state.active) SERIAL_PROTOCOLPGM("in");
+    if (!planner.leveling_active) SERIAL_PROTOCOLPGM("in");
     SERIAL_PROTOCOLLNPGM("active.");
     safe_delay(50);
   }
@@ -65,10 +65,9 @@
     safe_delay(10);
   }
 
-  ubl_state unified_bed_leveling::state;
+  int8_t unified_bed_leveling::storage_slot;
 
-  float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
-        unified_bed_leveling::last_specified_z;
+  float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
 
   // 15 is the maximum nubmer of grid points supported + 1 safety margin for now,
   // until determinism prevails
@@ -91,12 +90,11 @@
 
   void unified_bed_leveling::reset() {
     set_bed_leveling_enabled(false);
-    state.storage_slot = -1;
+    storage_slot = -1;
     #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      planner.z_fade_height = 10.0;
+      planner.set_z_fade_height(10.0);
     #endif
     ZERO(z_values);
-    last_specified_z = -999.9;
   }
 
   void unified_bed_leveling::invalidate() {
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h
index 1a83d7f17b..050a2dd664 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl.h
+++ b/Marlin/src/feature/bedlevel/ubl/ubl.h
@@ -70,16 +70,9 @@ extern uint8_t ubl_cnt;
 #define MESH_X_DIST (float(UBL_MESH_MAX_X - (UBL_MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
 #define MESH_Y_DIST (float(UBL_MESH_MAX_Y - (UBL_MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
 
-typedef struct {
-  bool active = false;
-  int8_t storage_slot = -1;
-} ubl_state;
-
 class unified_bed_leveling {
   private:
 
-    static float last_specified_z;
-
     static int    g29_verbose_level,
                   g29_phase_value,
                   g29_repetition_cnt,
@@ -161,7 +154,7 @@ class unified_bed_leveling {
       static void G26();
     #endif
 
-    static ubl_state state;
+    static int8_t storage_slot;
 
     static float z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
 
@@ -367,31 +360,6 @@ class unified_bed_leveling {
       return z0;
     }
 
-    /**
-     * This function sets the Z leveling fade factor based on the given Z height,
-     * only re-calculating when necessary.
-     *
-     *  Returns 1.0 if planner.z_fade_height is 0.0.
-     *  Returns 0.0 if Z is past the specified 'Fade Height'.
-     */
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      static inline float fade_scaling_factor_for_z(const float &lz) {
-        if (planner.z_fade_height == 0.0) return 1.0;
-        static float fade_scaling_factor = 1.0;
-        const float rz = RAW_Z_POSITION(lz);
-        if (last_specified_z != rz) {
-          last_specified_z = rz;
-          fade_scaling_factor =
-            rz < planner.z_fade_height
-              ? 1.0 - (rz * planner.inverse_z_fade_height)
-              : 0.0;
-        }
-        return fade_scaling_factor;
-      }
-    #else
-      FORCE_INLINE static float fade_scaling_factor_for_z(const float &lz) { return 1.0; }
-    #endif
-
     FORCE_INLINE static float mesh_index_to_xpos(const uint8_t i) {
       return i < GRID_MAX_POINTS_X ? pgm_read_float(&_mesh_index_to_xpos[i]) : UBL_MESH_MIN_X + i * (MESH_X_DIST);
     }
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
index 2c58750119..9c4f552160 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
@@ -424,8 +424,8 @@
     #endif // HAS_BED_PROBE
 
     if (parser.seen('P')) {
-      if (WITHIN(g29_phase_value, 0, 1) && state.storage_slot == -1) {
-        state.storage_slot = 0;
+      if (WITHIN(g29_phase_value, 0, 1) && storage_slot == -1) {
+        storage_slot = 0;
         SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.");
       }
 
@@ -604,7 +604,7 @@
     //
 
     if (parser.seen('L')) {     // Load Current Mesh Data
-      g29_storage_slot = parser.has_value() ? parser.value_int() : state.storage_slot;
+      g29_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
 
       int16_t a = settings.calc_num_meshes();
 
@@ -620,7 +620,7 @@
       }
 
       settings.load_mesh(g29_storage_slot);
-      state.storage_slot = g29_storage_slot;
+      storage_slot = g29_storage_slot;
 
       SERIAL_PROTOCOLLNPGM("Done.");
     }
@@ -630,7 +630,7 @@
     //
 
     if (parser.seen('S')) {     // Store (or Save) Current Mesh Data
-      g29_storage_slot = parser.has_value() ? parser.value_int() : state.storage_slot;
+      g29_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
 
       if (g29_storage_slot == -1) {                     // Special case, we are going to 'Export' the mesh to the
         SERIAL_ECHOLNPGM("G29 I 999");              // host in a form it can be reconstructed on a different machine
@@ -662,7 +662,7 @@
       }
 
       settings.store_mesh(g29_storage_slot);
-      state.storage_slot = g29_storage_slot;
+      storage_slot = g29_storage_slot;
 
       SERIAL_PROTOCOLLNPGM("Done.");
     }
@@ -1170,7 +1170,7 @@
 
       return;
     }
-    ubl_state_at_invocation = state.active;
+    ubl_state_at_invocation = planner.leveling_active;
     set_bed_leveling_enabled(false);
   }
 
@@ -1195,10 +1195,10 @@
   void unified_bed_leveling::g29_what_command() {
     report_state();
 
-    if (state.storage_slot == -1)
+    if (storage_slot == -1)
       SERIAL_PROTOCOLPGM("No Mesh Loaded.");
     else {
-      SERIAL_PROTOCOLPAIR("Mesh ", state.storage_slot);
+      SERIAL_PROTOCOLPAIR("Mesh ", storage_slot);
       SERIAL_PROTOCOLPGM(" Loaded.");
     }
     SERIAL_EOL();
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp
index 1fa97b43c2..977f2a865e 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp
@@ -173,7 +173,7 @@
       // are going to apply the Y-Distance into the cell to interpolate the final Z correction.
 
       const float yratio = (RAW_Y_POSITION(end[Y_AXIS]) - mesh_index_to_ypos(cell_dest_yi)) * (1.0 / (MESH_Y_DIST));
-      float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
+      float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * planner.fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
 
       /**
        * If part of the Mesh is undefined, it will show up as NAN
@@ -257,9 +257,8 @@
          */
         const float x = inf_m_flag ? start[X_AXIS] : (next_mesh_line_y - c) / m;
 
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi, current_yi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi, current_yi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -322,9 +321,8 @@
         const float next_mesh_line_x = LOGICAL_X_POSITION(mesh_index_to_xpos(current_xi)),
                     y = m * next_mesh_line_x + c;   // Calculate Y at the next X mesh line
 
-        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi, current_yi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi, current_yi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -395,9 +393,8 @@
 
       if (left_flag == (x > next_mesh_line_x)) { // Check if we hit the Y line first
         // Yes!  Crossing a Y Mesh Line next
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi - left_flag, current_yi + dyi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi - left_flag, current_yi + dyi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -423,9 +420,8 @@
       }
       else {
         // Yes!  Crossing a X Mesh Line next
-        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi + dxi, current_yi - down_flag);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi + dxi, current_yi - down_flag)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -580,17 +576,9 @@
             seg_rz = RAW_Z_POSITION(current_position[Z_AXIS]),
             seg_le = current_position[E_AXIS];
 
-      const bool above_fade_height = (
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-          planner.z_fade_height != 0 && planner.z_fade_height < RAW_Z_POSITION(ltarget[Z_AXIS])
-        #else
-          false
-        #endif
-      );
-
       // Only compute leveling per segment if ubl active and target below z_fade_height.
 
-      if (!state.active || above_fade_height) {   // no mesh leveling
+      if (!planner.leveling_active || !planner.leveling_active_at_z(ltarget[Z_AXIS])) {   // no mesh leveling
 
         do {
 
@@ -616,7 +604,7 @@
       // Otherwise perform per-segment leveling
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        const float fade_scaling_factor = fade_scaling_factor_for_z(ltarget[Z_AXIS]);
+        const float fade_scaling_factor = planner.fade_scaling_factor_for_z(ltarget[Z_AXIS]);
       #endif
 
       // increment to first segment destination
@@ -648,7 +636,7 @@
               z_x0y1 = z_values[cell_xi  ][cell_yi+1],  // z at lower right corner
               z_x1y1 = z_values[cell_xi+1][cell_yi+1];  // z at upper right corner
 
-        if (isnan(z_x0y0)) z_x0y0 = 0;              // ideally activating state.active (G29 A)
+        if (isnan(z_x0y0)) z_x0y0 = 0;              // ideally activating planner.leveling_active (G29 A)
         if (isnan(z_x1y0)) z_x1y0 = 0;              //   should refuse if any invalid mesh points
         if (isnan(z_x0y1)) z_x0y1 = 0;              //   in order to avoid isnan tests per cell,
         if (isnan(z_x1y1)) z_x1y1 = 0;              //   thus guessing zero for undefined points
diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp
index 994a37e170..30050ae9d1 100644
--- a/Marlin/src/gcode/bedlevel/M420.cpp
+++ b/Marlin/src/gcode/bedlevel/M420.cpp
@@ -51,7 +51,7 @@ void GcodeSuite::M420() {
     if (parser.seen('L')) {
 
       #if ENABLED(EEPROM_SETTINGS)
-        const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.state.storage_slot;
+        const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.storage_slot;
         const int16_t a = settings.calc_num_meshes();
 
         if (!a) {
@@ -66,7 +66,7 @@ void GcodeSuite::M420() {
         }
 
         settings.load_mesh(storage_slot);
-        ubl.state.storage_slot = storage_slot;
+        ubl.storage_slot = storage_slot;
 
       #else
 
@@ -80,7 +80,7 @@ void GcodeSuite::M420() {
     if (parser.seen('L') || parser.seen('V')) {
       ubl.display_map(0);  // Currently only supports one map type
       SERIAL_ECHOLNPAIR("ubl.mesh_is_valid = ", ubl.mesh_is_valid());
-      SERIAL_ECHOLNPAIR("ubl.state.storage_slot = ", ubl.state.storage_slot);
+      SERIAL_ECHOLNPAIR("ubl.storage_slot = ", ubl.storage_slot);
     }
 
   #endif // AUTO_BED_LEVELING_UBL
@@ -105,14 +105,13 @@ void GcodeSuite::M420() {
   }
 
   const bool to_enable = parser.boolval('S');
-  if (parser.seen('S'))
-    set_bed_leveling_enabled(to_enable);
+  if (parser.seen('S')) set_bed_leveling_enabled(to_enable);
 
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
     if (parser.seen('Z')) set_z_fade_height(parser.value_linear_units());
   #endif
 
-  const bool new_status = leveling_is_active();
+  const bool new_status = planner.leveling_active;
 
   if (to_enable && !new_status) {
     SERIAL_ERROR_START();
diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp
index fa1c70c85c..7f6289ce8f 100644
--- a/Marlin/src/gcode/bedlevel/abl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp
@@ -137,7 +137,7 @@ void GcodeSuite::G29() {
     const uint8_t old_debug_flags = marlin_debug_flags;
     if (query) marlin_debug_flags |= DEBUG_LEVELING;
     if (DEBUGGING(LEVELING)) {
-      DEBUG_POS(">>> gcode_G29", current_position);
+      DEBUG_POS(">>> G29", current_position);
       log_machine_info();
     }
     marlin_debug_flags = old_debug_flags;
@@ -247,7 +247,7 @@ void GcodeSuite::G29() {
       abl_probe_index = -1;
     #endif
 
-    abl_should_enable = leveling_is_active();
+    abl_should_enable = planner.leveling_active;
 
     #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
 
@@ -388,7 +388,7 @@ void GcodeSuite::G29() {
     stepper.synchronize();
 
     // Disable auto bed leveling during G29
-    planner.abl_enabled = false;
+    planner.leveling_active = false;
 
     if (!dryrun) {
       // Re-orient the current position without leveling
@@ -402,7 +402,7 @@ void GcodeSuite::G29() {
     #if HAS_BED_PROBE
       // Deploy the probe. Probe will raise if needed.
       if (DEPLOY_PROBE()) {
-        planner.abl_enabled = abl_should_enable;
+        planner.leveling_active = abl_should_enable;
         return;
       }
     #endif
@@ -421,7 +421,7 @@ void GcodeSuite::G29() {
       ) {
         if (dryrun) {
           // Before reset bed level, re-enable to correct the position
-          planner.abl_enabled = abl_should_enable;
+          planner.leveling_active = abl_should_enable;
         }
         // Reset grid to 0.0 or "not probed". (Also disables ABL)
         reset_bed_level();
@@ -466,7 +466,7 @@ void GcodeSuite::G29() {
       #if HAS_SOFTWARE_ENDSTOPS
         soft_endstops_enabled = enable_soft_endstops;
       #endif
-      planner.abl_enabled = abl_should_enable;
+      planner.leveling_active = abl_should_enable;
       g29_in_progress = false;
       #if ENABLED(LCD_BED_LEVELING)
         lcd_wait_for_move = false;
@@ -669,7 +669,7 @@ void GcodeSuite::G29() {
           measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
 
           if (isnan(measured_z)) {
-            planner.abl_enabled = abl_should_enable;
+            planner.leveling_active = abl_should_enable;
             break;
           }
 
@@ -705,7 +705,7 @@ void GcodeSuite::G29() {
         yProbe = LOGICAL_Y_POSITION(points[i].y);
         measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
         if (isnan(measured_z)) {
-          planner.abl_enabled = abl_should_enable;
+          planner.leveling_active = abl_should_enable;
           break;
         }
         points[i].z = measured_z;
@@ -728,7 +728,7 @@ void GcodeSuite::G29() {
 
     // Raise to _Z_CLEARANCE_DEPLOY_PROBE. Stow the probe.
     if (STOW_PROBE()) {
-      planner.abl_enabled = abl_should_enable;
+      planner.leveling_active = abl_should_enable;
       measured_z = NAN;
     }
   }
@@ -896,9 +896,9 @@ void GcodeSuite::G29() {
         float converted[XYZ];
         COPY(converted, current_position);
 
-        planner.abl_enabled = true;
+        planner.leveling_active = true;
         planner.unapply_leveling(converted); // use conversion machinery
-        planner.abl_enabled = false;
+        planner.leveling_active = false;
 
         // Use the last measured distance to the bed, if possible
         if ( NEAR(current_position[X_AXIS], xProbe - (X_PROBE_OFFSET_FROM_EXTRUDER))
@@ -950,21 +950,21 @@ void GcodeSuite::G29() {
     #endif
 
     // Auto Bed Leveling is complete! Enable if possible.
-    planner.abl_enabled = dryrun ? abl_should_enable : true;
+    planner.leveling_active = dryrun ? abl_should_enable : true;
   } // !isnan(measured_z)
 
   // Restore state after probing
   if (!faux) clean_up_after_endstop_or_probe_move();
 
   #if ENABLED(DEBUG_LEVELING_FEATURE)
-    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< gcode_G29");
+    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G29");
   #endif
 
   report_current_position();
 
   KEEPALIVE_STATE(IN_HANDLER);
 
-  if (planner.abl_enabled)
+  if (planner.leveling_active)
     SYNC_PLAN_POSITION_KINEMATIC();
 }
 
diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
index 64ff57e2b4..58128aee76 100644
--- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
@@ -42,7 +42,7 @@
 void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
 
 void mesh_probing_done() {
-  mbl.set_has_mesh(true);
+  mbl.has_mesh = true;
   gcode.home_all_axes();
   set_bed_leveling_enabled(true);
   #if ENABLED(MESH_G28_REST_ORIGIN)
@@ -92,7 +92,7 @@ void GcodeSuite::G29() {
   switch (state) {
     case MeshReport:
       if (leveling_is_valid()) {
-        SERIAL_PROTOCOLLNPAIR("State: ", leveling_is_active() ? MSG_ON : MSG_OFF);
+        SERIAL_PROTOCOLLNPAIR("State: ", planner.leveling_active ? MSG_ON : MSG_OFF);
         mbl_mesh_report();
       }
       else
diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp
index df4109a03b..effa484d2b 100644
--- a/Marlin/src/gcode/calibrate/G28.cpp
+++ b/Marlin/src/gcode/calibrate/G28.cpp
@@ -157,7 +157,7 @@ void GcodeSuite::G28(const bool always_home_all) {
   // Disable the leveling matrix before homing
   #if HAS_LEVELING
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      const bool ubl_state_at_entry = leveling_is_active();
+      const bool ubl_state_at_entry = planner.leveling_active;
     #endif
     set_bed_leveling_enabled(false);
   #endif
diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp
index 4c32933b00..a910f02ee6 100644
--- a/Marlin/src/gcode/calibrate/M48.cpp
+++ b/Marlin/src/gcode/calibrate/M48.cpp
@@ -32,6 +32,10 @@
   #include "../../feature/bedlevel/bedlevel.h"
 #endif
 
+#if HAS_LEVELING
+  #include "../../module/planner.h"
+#endif
+
 /**
  * M48: Z probe repeatability measurement function.
  *
@@ -115,7 +119,7 @@ void GcodeSuite::M48() {
   // Disable bed level correction in M48 because we want the raw data when we probe
 
   #if HAS_LEVELING
-    const bool was_enabled = leveling_is_active();
+    const bool was_enabled = planner.leveling_active;
     set_bed_leveling_enabled(false);
   #endif
 
diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp
index 24cd62c701..3911b8fbc4 100644
--- a/Marlin/src/gcode/control/T.cpp
+++ b/Marlin/src/gcode/control/T.cpp
@@ -37,7 +37,7 @@ void GcodeSuite::T(const uint8_t tmp_extruder) {
 
   #if ENABLED(DEBUG_LEVELING_FEATURE)
     if (DEBUGGING(LEVELING)) {
-      SERIAL_ECHOPAIR(">>> gcode_T(", tmp_extruder);
+      SERIAL_ECHOPAIR(">>> T(", tmp_extruder);
       SERIAL_CHAR(')');
       SERIAL_EOL();
       DEBUG_POS("BEFORE", current_position);
@@ -61,7 +61,7 @@ void GcodeSuite::T(const uint8_t tmp_extruder) {
   #if ENABLED(DEBUG_LEVELING_FEATURE)
     if (DEBUGGING(LEVELING)) {
       DEBUG_POS("AFTER", current_position);
-      SERIAL_ECHOLNPGM("<<< gcode_T");
+      SERIAL_ECHOLNPGM("<<< T()");
     }
   #endif
 }
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index 32ec40cb9f..6619a3bb8d 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -820,12 +820,12 @@
   #define UBL_DELTA  (ENABLED(AUTO_BED_LEVELING_UBL) && (ENABLED(DELTA) || ENABLED(UBL_GRANULAR_SEGMENTATION_FOR_CARTESIAN)))
   #define ABL_PLANAR (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT))
   #define ABL_GRID   (ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR))
-  #define HAS_ABL    (ABL_PLANAR || ABL_GRID || ENABLED(AUTO_BED_LEVELING_UBL))
-  #define HAS_LEVELING  (HAS_ABL || ENABLED(MESH_BED_LEVELING))
-  #define HAS_AUTOLEVEL (HAS_ABL && DISABLED(PROBE_MANUALLY))
-  #define OLDSCHOOL_ABL (HAS_ABL && DISABLED(AUTO_BED_LEVELING_UBL))
-  #define HAS_MESH   (ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(MESH_BED_LEVELING))
-  #define PLANNER_LEVELING      (ABL_PLANAR || ABL_GRID || ENABLED(MESH_BED_LEVELING) || UBL_DELTA)
+  #define OLDSCHOOL_ABL         (ABL_PLANAR || ABL_GRID)
+  #define HAS_ABL               (OLDSCHOOL_ABL || ENABLED(AUTO_BED_LEVELING_UBL))
+  #define HAS_LEVELING          (HAS_ABL || ENABLED(MESH_BED_LEVELING))
+  #define HAS_AUTOLEVEL         (HAS_ABL && DISABLED(PROBE_MANUALLY))
+  #define HAS_MESH              (ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(MESH_BED_LEVELING))
+  #define PLANNER_LEVELING      (OLDSCHOOL_ABL || ENABLED(MESH_BED_LEVELING) || UBL_DELTA)
   #define HAS_PROBING_PROCEDURE (HAS_ABL || ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST))
   #if HAS_PROBING_PROCEDURE
     #define PROBE_BED_WIDTH abs(RIGHT_PROBE_BED_POSITION - (LEFT_PROBE_BED_POSITION))
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 182ac194c5..b05e3e6031 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -651,7 +651,7 @@ static_assert(1 >= 0
   /**
    * Require some kind of probe for bed leveling and probe testing
    */
-  #if HAS_ABL && DISABLED(AUTO_BED_LEVELING_UBL)
+  #if OLDSCHOOL_ABL
     #error "Auto Bed Leveling requires one of these: PROBE_MANUALLY, FIX_MOUNTED_PROBE, BLTOUCH, SOLENOID_PROBE, Z_PROBE_ALLEN_KEY, Z_PROBE_SLED, or a Z Servo."
   #endif
 
diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp
index 6a3728cc92..3931a8f48a 100644
--- a/Marlin/src/lcd/ultralcd.cpp
+++ b/Marlin/src/lcd/ultralcd.cpp
@@ -1086,7 +1086,7 @@ void kill_screen(const char* lcd_msg) {
           const float new_zoffset = zprobe_zoffset + planner.steps_to_mm[Z_AXIS] * babystep_increment;
           if (WITHIN(new_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) {
 
-            if (leveling_is_active())
+            if (planner.leveling_active)
               thermalManager.babystep_axis(Z_AXIS, babystep_increment);
 
             zprobe_zoffset = new_zoffset;
@@ -1788,7 +1788,7 @@ void kill_screen(const char* lcd_msg) {
 
             _lcd_after_probing();
 
-            mbl.set_has_mesh(true);
+            mbl.has_mesh = true;
             mesh_probing_done();
 
           #endif
@@ -1906,11 +1906,12 @@ void kill_screen(const char* lcd_msg) {
       enqueue_and_echo_commands_P(PSTR("G28"));
     }
 
-    static bool _level_state;
-    void _lcd_toggle_bed_leveling() { set_bed_leveling_enabled(_level_state); }
+    static bool new_level_state;
+    void _lcd_toggle_bed_leveling() { set_bed_leveling_enabled(new_level_state); }
 
     #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      void _lcd_set_z_fade_height() { set_z_fade_height(planner.z_fade_height); }
+      static float new_z_fade_height;
+      void _lcd_set_z_fade_height() { set_z_fade_height(new_z_fade_height); }
     #endif
 
     /**
@@ -1934,13 +1935,11 @@ void kill_screen(const char* lcd_msg) {
       if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]))
         MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
       else if (leveling_is_valid()) {
-        _level_state = leveling_is_active();
-        MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &_level_state, _lcd_toggle_bed_leveling);
+        MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &new_level_state, _lcd_toggle_bed_leveling);
       }
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        set_z_fade_height(planner.z_fade_height);
-        MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_Z_FADE_HEIGHT, &planner.z_fade_height, 0.0, 100.0, _lcd_set_z_fade_height);
+        MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_Z_FADE_HEIGHT, &new_z_fade_height, 0.0, 100.0, _lcd_set_z_fade_height);
       #endif
 
       //
@@ -1971,6 +1970,16 @@ void kill_screen(const char* lcd_msg) {
       END_MENU();
     }
 
+    void _lcd_goto_bed_leveling() {
+      currentScreen = lcd_bed_leveling;
+      #if ENABLED(LCD_BED_LEVELING)
+        new_level_state = planner.leveling_active;
+      #endif
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+        new_z_fade_height = planner.z_fade_height;
+      #endif
+    }
+
   #elif ENABLED(AUTO_BED_LEVELING_UBL)
 
     void _lcd_ubl_level_bed();
@@ -2541,7 +2550,13 @@ void kill_screen(const char* lcd_msg) {
       #if ENABLED(PROBE_MANUALLY)
         if (!g29_in_progress)
       #endif
-      MENU_ITEM(submenu, MSG_BED_LEVELING, lcd_bed_leveling);
+          MENU_ITEM(submenu, MSG_BED_LEVELING,
+            #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+              _lcd_goto_bed_leveling
+            #else
+              lcd_bed_leveling
+            #endif
+          );
     #else
       #if PLANNER_LEVELING
         MENU_ITEM(gcode, MSG_BED_LEVELING, PSTR("G28\nG29"));
diff --git a/Marlin/src/lcd/ultralcd_impl_HD44780.h b/Marlin/src/lcd/ultralcd_impl_HD44780.h
index 488e3f1953..7cf64789b8 100644
--- a/Marlin/src/lcd/ultralcd_impl_HD44780.h
+++ b/Marlin/src/lcd/ultralcd_impl_HD44780.h
@@ -795,7 +795,7 @@ static void lcd_implementation_status_screen() {
     lcd.print(ftostr52sp(FIXFLOAT(current_position[Z_AXIS])));
 
     #if HAS_LEVELING
-      lcd.write(leveling_is_active() || blink ? '_' : ' ');
+      lcd.write(planner.leveling_active || blink ? '_' : ' ');
     #endif
 
   #endif // LCD_HEIGHT > 2
diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp
index 88bd2ad867..4a37e477e8 100644
--- a/Marlin/src/module/configuration_store.cpp
+++ b/Marlin/src/module/configuration_store.cpp
@@ -68,7 +68,7 @@
  *  219            z_fade_height                    (float)
  *
  * MESH_BED_LEVELING:                               43 bytes
- *  223  M420 S    from mbl.status                  (bool)
+ *  223  M420 S    planner.leveling_active         (bool)
  *  224            mbl.z_offset                     (float)
  *  228            GRID_MAX_POINTS_X                (uint8_t)
  *  229            GRID_MAX_POINTS_Y                (uint8_t)
@@ -88,8 +88,8 @@
  *  316            z_values[][]                     (float x9, up to float x256) +988
  *
  * AUTO_BED_LEVELING_UBL:                           2 bytes
- *  324  G29 A     ubl.state.active                 (bool)
- *  325  G29 S     ubl.state.storage_slot           (int8_t)
+ *  324  G29 A     planner.leveling_active          (bool)
+ *  325  G29 S     ubl.storage_slot                 (int8_t)
  *
  * DELTA:                                           48 bytes
  *  344  M666 XYZ  delta_endstop_adj                (float x3)
@@ -202,6 +202,10 @@ MarlinSettings settings;
   #include "../feature/fwretract.h"
 #endif
 
+#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+  float new_z_fade_height;
+#endif
+
 /**
  * Post-process after Retrieve or Reset
  */
@@ -231,7 +235,7 @@ void MarlinSettings::postprocess() {
   #endif
 
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-    set_z_fade_height(planner.z_fade_height);
+    set_z_fade_height(new_z_fade_height);
   #endif
 
   #if HAS_BED_PROBE
@@ -329,7 +333,7 @@ void MarlinSettings::postprocess() {
     #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
       const float zfh = planner.z_fade_height;
     #else
-      const float zfh = 10.0;
+      const float zfh = 0.0;
     #endif
     EEPROM_WRITE(zfh);
 
@@ -343,7 +347,7 @@ void MarlinSettings::postprocess() {
         sizeof(mbl.z_values) == GRID_MAX_POINTS * sizeof(mbl.z_values[0][0]),
         "MBL Z array is the wrong size."
       );
-      const bool leveling_is_on = TEST(mbl.status, MBL_STATUS_HAS_MESH_BIT);
+      const bool leveling_is_on = mbl.has_mesh;
       const uint8_t mesh_num_x = GRID_MAX_POINTS_X, mesh_num_y = GRID_MAX_POINTS_Y;
       EEPROM_WRITE(leveling_is_on);
       EEPROM_WRITE(mbl.z_offset);
@@ -406,8 +410,8 @@ void MarlinSettings::postprocess() {
     #endif // AUTO_BED_LEVELING_BILINEAR
 
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      EEPROM_WRITE(ubl.state.active);
-      EEPROM_WRITE(ubl.state.storage_slot);
+      EEPROM_WRITE(planner.leveling_active);
+      EEPROM_WRITE(ubl.storage_slot);
     #else
       const bool ubl_active = false;
       const int8_t storage_slot = -1;
@@ -630,8 +634,8 @@ void MarlinSettings::postprocess() {
     }
 
     #if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
-      if (ubl.state.storage_slot >= 0)
-        store_mesh(ubl.state.storage_slot);
+      if (ubl.storage_slot >= 0)
+        store_mesh(ubl.storage_slot);
     #endif
     EEPROM_FINISH();
     return !eeprom_error;
@@ -720,7 +724,7 @@ void MarlinSettings::postprocess() {
       //
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        EEPROM_READ(planner.z_fade_height);
+        EEPROM_READ(new_z_fade_height);
       #else
         EEPROM_READ(dummy);
       #endif
@@ -737,7 +741,7 @@ void MarlinSettings::postprocess() {
       EEPROM_READ(mesh_num_y);
 
       #if ENABLED(MESH_BED_LEVELING)
-        mbl.status = leveling_is_on ? _BV(MBL_STATUS_HAS_MESH_BIT) : 0;
+        mbl.has_mesh = leveling_is_on;
         mbl.z_offset = dummy;
         if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
           // EEPROM data fits the current mesh
@@ -793,8 +797,8 @@ void MarlinSettings::postprocess() {
         }
 
       #if ENABLED(AUTO_BED_LEVELING_UBL)
-        EEPROM_READ(ubl.state.active);
-        EEPROM_READ(ubl.state.storage_slot);
+        EEPROM_READ(planner.leveling_active);
+        EEPROM_READ(ubl.storage_slot);
       #else
         uint8_t dummyui8;
         EEPROM_READ(dummyb);
@@ -1011,10 +1015,10 @@ void MarlinSettings::postprocess() {
           ubl.reset();
         }
 
-        if (ubl.state.storage_slot >= 0) {
-          load_mesh(ubl.state.storage_slot);
+        if (ubl.storage_slot >= 0) {
+          load_mesh(ubl.storage_slot);
           #if ENABLED(EEPROM_CHITCHAT)
-            SERIAL_ECHOPAIR("Mesh ", ubl.state.storage_slot);
+            SERIAL_ECHOPAIR("Mesh ", ubl.storage_slot);
             SERIAL_ECHOLNPGM(" loaded from storage.");
           #endif
         }
@@ -1156,7 +1160,7 @@ void MarlinSettings::reset() {
   planner.max_jerk[E_AXIS] = DEFAULT_EJERK;
 
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-    planner.z_fade_height = 0.0;
+    new_z_fade_height = 0.0;
   #endif
 
   #if HAS_HOME_OFFSET
@@ -1556,9 +1560,9 @@ void MarlinSettings::reset() {
         SERIAL_ECHOLNPGM(":");
       }
       CONFIG_ECHO_START;
-      SERIAL_ECHOPAIR("  M420 S", leveling_is_active() ? 1 : 0);
+      SERIAL_ECHOPAIR("  M420 S", planner.leveling_active ? 1 : 0);
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        SERIAL_ECHOPAIR(" Z", planner.z_fade_height);
+        SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.z_fade_height));
       #endif
       SERIAL_EOL();
 
@@ -1566,7 +1570,7 @@ void MarlinSettings::reset() {
         SERIAL_EOL();
         ubl.report_state();
 
-        SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.state.storage_slot);
+        SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.storage_slot);
         SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
         SERIAL_ECHOLNPGM(" meshes.\n");
       }
@@ -1578,7 +1582,7 @@ void MarlinSettings::reset() {
         SERIAL_ECHOLNPGM("Auto Bed Leveling:");
       }
       CONFIG_ECHO_START;
-      SERIAL_ECHOPAIR("  M420 S", leveling_is_active() ? 1 : 0);
+      SERIAL_ECHOPAIR("  M420 S", planner.leveling_active ? 1 : 0);
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
         SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.z_fade_height));
       #endif
diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp
index 87cf0b9bf0..ecc3f8bf97 100644
--- a/Marlin/src/module/motion.cpp
+++ b/Marlin/src/module/motion.cpp
@@ -490,14 +490,14 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
   #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
     #if ENABLED(DELTA)
       #define ADJUST_DELTA(V) \
-        if (planner.abl_enabled) { \
+        if (planner.leveling_active) { \
           const float zadj = bilinear_z_offset(V); \
           delta[A_AXIS] += zadj; \
           delta[B_AXIS] += zadj; \
           delta[C_AXIS] += zadj; \
         }
     #else
-      #define ADJUST_DELTA(V) if (planner.abl_enabled) { delta[Z_AXIS] += bilinear_z_offset(V); }
+      #define ADJUST_DELTA(V) if (planner.leveling_active) { delta[Z_AXIS] += bilinear_z_offset(V); }
     #endif
   #else
     #define ADJUST_DELTA(V) NOOP
@@ -630,41 +630,30 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
 
   /**
    * Prepare a linear move in a Cartesian setup.
-   * If Mesh Bed Leveling is enabled, perform a mesh move.
+   * Bed Leveling will be applied to the move if enabled.
    *
-   * Returns true if the caller didn't update current_position.
+   * Returns true if current_position[] was set to destination[]
    */
   inline bool prepare_move_to_destination_cartesian() {
-    #if ENABLED(AUTO_BED_LEVELING_UBL)
+    if (current_position[X_AXIS] != destination[X_AXIS] || current_position[Y_AXIS] != destination[Y_AXIS]) {
       const float fr_scaled = MMS_SCALED(feedrate_mm_s);
-      if (ubl.state.active) { // direct use of ubl.state.active for speed
-        ubl.line_to_destination_cartesian(fr_scaled, active_extruder);
-        return true;
-      }
-      else
-        line_to_destination(fr_scaled);
-    #else
-      // Do not use feedrate_percentage for E or Z only moves
-      if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS])
-        line_to_destination();
-      else {
-        const float fr_scaled = MMS_SCALED(feedrate_mm_s);
-        #if ENABLED(MESH_BED_LEVELING)
-          if (mbl.active()) { // direct used of mbl.active() for speed
+      #if HAS_MESH
+        if (planner.leveling_active) {
+          #if ENABLED(AUTO_BED_LEVELING_UBL)
+            ubl.line_to_destination_cartesian(fr_scaled, active_extruder);
+          #elif ENABLED(MESH_BED_LEVELING)
             mesh_line_to_destination(fr_scaled);
-            return true;
-          }
-          else
-        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
-          if (planner.abl_enabled) { // direct use of abl_enabled for speed
+          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
             bilinear_line_to_destination(fr_scaled);
-            return true;
-          }
-          else
-        #endif
-            line_to_destination(fr_scaled);
-      }
-    #endif
+          #endif
+          return true;
+        }
+      #endif // HAS_MESH
+      line_to_destination(fr_scaled);
+    }
+    else
+      line_to_destination();
+
     return false;
   }
 
@@ -699,6 +688,8 @@ float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
 
   /**
    * Prepare a linear move in a dual X axis setup
+   *
+   * Return true if current_position[] was set to destination[]
    */
   inline bool prepare_move_to_destination_dualx() {
     if (active_extruder_parked) {
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index 7d55a0df9e..7da09c8c1f 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -122,8 +122,8 @@ float Planner::min_feedrate_mm_s,
       Planner::max_jerk[XYZE],       // The largest speed change requiring no acceleration
       Planner::min_travel_feedrate_mm_s;
 
-#if OLDSCHOOL_ABL
-  bool Planner::abl_enabled = false; // Flag that auto bed leveling is enabled
+#if HAS_LEVELING
+  bool Planner::leveling_active = false; // Flag that auto bed leveling is enabled
   #if ABL_PLANAR
     matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
   #endif
@@ -131,7 +131,8 @@ float Planner::min_feedrate_mm_s,
 
 #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
   float Planner::z_fade_height, // Initialized by settings.load()
-        Planner::inverse_z_fade_height;
+        Planner::inverse_z_fade_height,
+        Planner::last_raw_lz;
 #endif
 
 #if ENABLED(AUTOTEMP)
@@ -555,46 +556,31 @@ void Planner::calculate_volumetric_multipliers() {
    */
   void Planner::apply_leveling(float &lx, float &ly, float &lz) {
 
+    if (!planner.leveling_active) return;
+
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      const float fade_scaling_factor = fade_scaling_factor_for_z(lz);
+      if (!fade_scaling_factor) return;
+    #else
+      constexpr float fade_scaling_factor = 1.0;
+    #endif
+
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      if (!ubl.state.active) return;
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        // if z_fade_height enabled (nonzero) and raw_z above it, no leveling required
-        if (planner.z_fade_height && planner.z_fade_height <= RAW_Z_POSITION(lz)) return;
-        lz += ubl.get_z_correction(lx, ly) * ubl.fade_scaling_factor_for_z(lz);
-      #else // no fade
-        lz += ubl.get_z_correction(lx, ly);
-      #endif // FADE
-    #endif // UBL
 
-    #if OLDSCHOOL_ABL
-      if (!abl_enabled) return;
-    #endif
+      lz += ubl.get_z_correction(lx, ly) * fade_scaling_factor;
 
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) && DISABLED(AUTO_BED_LEVELING_UBL)
-      static float z_fade_factor = 1.0, last_raw_lz = -999.0;
-      if (z_fade_height) {
-        const float raw_lz = RAW_Z_POSITION(lz);
-        if (raw_lz >= z_fade_height) return;
-        if (last_raw_lz != raw_lz) {
-          last_raw_lz = raw_lz;
-          z_fade_factor = 1.0 - raw_lz * inverse_z_fade_height;
-        }
-      }
-      else
-        z_fade_factor = 1.0;
-    #endif
+    #elif ENABLED(MESH_BED_LEVELING)
 
-    #if ENABLED(MESH_BED_LEVELING)
-
-      if (mbl.active())
-        lz += mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly)
-          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-            , z_fade_factor
-          #endif
-          );
+      lz += mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly)
+        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+          , fade_scaling_factor
+        #endif
+      );
 
     #elif ABL_PLANAR
 
+      UNUSED(fade_scaling_factor);
+
       float dx = RAW_X_POSITION(lx) - (X_TILT_FULCRUM),
             dy = RAW_Y_POSITION(ly) - (Y_TILT_FULCRUM),
             dz = RAW_Z_POSITION(lz);
@@ -608,70 +594,55 @@ void Planner::calculate_volumetric_multipliers() {
     #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
 
       float tmp[XYZ] = { lx, ly, 0 };
-      lz += bilinear_z_offset(tmp)
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-          * z_fade_factor
-        #endif
-      ;
+      lz += bilinear_z_offset(tmp) * fade_scaling_factor;
 
     #endif
   }
 
   void Planner::unapply_leveling(float logical[XYZ]) {
 
-    #if ENABLED(AUTO_BED_LEVELING_UBL)
-
-      if (ubl.state.active) {
-
-        const float z_physical = RAW_Z_POSITION(logical[Z_AXIS]),
-                    z_correct = ubl.get_z_correction(logical[X_AXIS], logical[Y_AXIS]),
-                    z_virtual = z_physical - z_correct;
-              float z_logical = LOGICAL_Z_POSITION(z_virtual);
-
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-
-          // for P=physical_z, L=logical_z, M=mesh_z, H=fade_height,
-          // Given P=L+M(1-L/H) (faded mesh correction formula for L<H)
-          //  then L=P-M(1-L/H)
-          //    so L=P-M+ML/H
-          //    so L-ML/H=P-M
-          //    so L(1-M/H)=P-M
-          //    so L=(P-M)/(1-M/H) for L<H
-
-          if (planner.z_fade_height) {
-            if (z_logical >= planner.z_fade_height)
-              z_logical = LOGICAL_Z_POSITION(z_physical);
-            else
-              z_logical /= 1.0 - z_correct * planner.inverse_z_fade_height;
-          }
-
-        #endif // ENABLE_LEVELING_FADE_HEIGHT
-
-        logical[Z_AXIS] = z_logical;
-      }
-
-      return; // don't fall thru to other ENABLE_LEVELING_FADE_HEIGHT logic
-
-    #endif
-
-    #if OLDSCHOOL_ABL
-      if (!abl_enabled) return;
-    #endif
+    if (!planner.leveling_active) return;
 
     #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
       if (z_fade_height && RAW_Z_POSITION(logical[Z_AXIS]) >= z_fade_height) return;
     #endif
 
-    #if ENABLED(MESH_BED_LEVELING)
+    #if ENABLED(AUTO_BED_LEVELING_UBL)
 
-      if (mbl.active()) {
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-          const float c = mbl.get_z(RAW_X_POSITION(logical[X_AXIS]), RAW_Y_POSITION(logical[Y_AXIS]), 1.0);
-          logical[Z_AXIS] = (z_fade_height * (RAW_Z_POSITION(logical[Z_AXIS]) - c)) / (z_fade_height - c);
-        #else
-          logical[Z_AXIS] -= mbl.get_z(RAW_X_POSITION(logical[X_AXIS]), RAW_Y_POSITION(logical[Y_AXIS]));
-        #endif
-      }
+      const float z_physical = RAW_Z_POSITION(logical[Z_AXIS]),
+                  z_correct = ubl.get_z_correction(logical[X_AXIS], logical[Y_AXIS]),
+                  z_virtual = z_physical - z_correct;
+            float z_logical = LOGICAL_Z_POSITION(z_virtual);
+
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+
+        // for P=physical_z, L=logical_z, M=mesh_z, H=fade_height,
+        // Given P=L+M(1-L/H) (faded mesh correction formula for L<H)
+        //  then L=P-M(1-L/H)
+        //    so L=P-M+ML/H
+        //    so L-ML/H=P-M
+        //    so L(1-M/H)=P-M
+        //    so L=(P-M)/(1-M/H) for L<H
+
+        if (planner.z_fade_height) {
+          if (z_logical >= planner.z_fade_height)
+            z_logical = LOGICAL_Z_POSITION(z_physical);
+          else
+            z_logical /= 1.0 - z_correct * planner.inverse_z_fade_height;
+        }
+
+      #endif // ENABLE_LEVELING_FADE_HEIGHT
+
+      logical[Z_AXIS] = z_logical;
+
+    #elif ENABLED(MESH_BED_LEVELING)
+
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+        const float c = mbl.get_z(RAW_X_POSITION(logical[X_AXIS]), RAW_Y_POSITION(logical[Y_AXIS]), 1.0);
+        logical[Z_AXIS] = (z_fade_height * (RAW_Z_POSITION(logical[Z_AXIS]) - c)) / (z_fade_height - c);
+      #else
+        logical[Z_AXIS] -= mbl.get_z(RAW_X_POSITION(logical[X_AXIS]), RAW_Y_POSITION(logical[Y_AXIS]));
+      #endif
 
     #elif ABL_PLANAR
 
diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h
index 85f35f35b8..36f4e4e9a0 100644
--- a/Marlin/src/module/planner.h
+++ b/Marlin/src/module/planner.h
@@ -164,15 +164,14 @@ class Planner {
                  max_jerk[XYZE],       // The largest speed change requiring no acceleration
                  min_travel_feedrate_mm_s;
 
-    #if OLDSCHOOL_ABL
-      static bool abl_enabled;              // Flag that bed leveling is enabled
+    #if HAS_LEVELING
+      static bool leveling_active;              // Flag that bed leveling is enabled
       #if ABL_PLANAR
         static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
       #endif
-    #endif
-
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      static float z_fade_height, inverse_z_fade_height;
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+        static float z_fade_height, inverse_z_fade_height;
+      #endif
     #endif
 
     #if ENABLED(LIN_ADVANCE)
@@ -202,6 +201,10 @@ class Planner {
      */
     static uint32_t cutoff_long;
 
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      static float last_raw_lz;
+    #endif
+
     #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
       /**
        * Counters to manage disabling inactive extruders
@@ -263,6 +266,52 @@ class Planner {
         if (!filament_size[i]) filament_size[i] = DEFAULT_NOMINAL_FILAMENT_DIA;
     }
 
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+
+      /**
+       * Get the Z leveling fade factor based on the given Z height,
+       * re-calculating only when needed.
+       *
+       *  Returns 1.0 if planner.z_fade_height is 0.0.
+       *  Returns 0.0 if Z is past the specified 'Fade Height'.
+       */
+      inline static float fade_scaling_factor_for_z(const float &lz) {
+        static float z_fade_factor = 1.0;
+        if (z_fade_height) {
+          const float raw_lz = RAW_Z_POSITION(lz);
+          if (raw_lz >= z_fade_height) return 0.0;
+          if (last_raw_lz != raw_lz) {
+            last_raw_lz = raw_lz;
+            z_fade_factor = 1.0 - raw_lz * inverse_z_fade_height;
+          }
+          return z_fade_factor;
+        }
+        return 1.0;
+      }
+
+      FORCE_INLINE static void force_fade_recalc() { last_raw_lz = -999.999; }
+
+      FORCE_INLINE static void set_z_fade_height(const float &zfh) {
+        z_fade_height = zfh > 0 ? zfh : 0;
+        inverse_z_fade_height = RECIPROCAL(z_fade_height);
+        force_fade_recalc();
+      }
+
+      FORCE_INLINE static bool leveling_active_at_z(const float &lz) {
+        return !z_fade_height || RAW_Z_POSITION(lz) < z_fade_height;
+      }
+
+    #else
+
+      FORCE_INLINE static float fade_scaling_factor_for_z(const float &lz) {
+        UNUSED(lz);
+        return 1.0;
+      }
+
+      FORCE_INLINE static bool leveling_active_at_z(const float &lz) { return true; }
+
+    #endif
+
     #if PLANNER_LEVELING
 
       #define ARG_X float lx
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index 98185f6a5b..9c7cc3371f 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -679,7 +679,7 @@ void refresh_zprobe_zoffset(const bool no_babystep/*=false*/) {
     #endif
 
     #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
-      if (!no_babystep && leveling_is_active())
+      if (!no_babystep && planner.leveling_active)
         thermalManager.babystep_axis(Z_AXIS, -LROUND(diff * planner.axis_steps_per_mm[Z_AXIS]));
     #else
       UNUSED(no_babystep);
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 7eec289903..7be79c4513 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -2059,7 +2059,8 @@ void Temperature::isr() {
   } // temp_count >= OVERSAMPLENR
 
   // Go to the next state, up to SensorsReady
-  adc_sensor_state = (ADCSensorState)((int(adc_sensor_state) + 1) % int(StartupDelay));
+  adc_sensor_state = (ADCSensorState)(int(adc_sensor_state) + 1);
+  if (adc_sensor_state > SensorsReady) adc_sensor_state = (ADCSensorState)0;
 
   #if ENABLED(BABYSTEPPING)
     LOOP_XYZ(axis) {
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 758044292c..75fba3d94b 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -295,13 +295,13 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
                                     + (tmp_extruder == 0 ? -(PARKING_EXTRUDER_GRAB_DISTANCE) : PARKING_EXTRUDER_GRAB_DISTANCE);
               /**
                *  Steps:
-               *    1. raise Z-Axis to have enough clearance
-               *    2. move to park poition of old extruder
-               *    3. disengage magnetc field, wait for delay
-               *    4. move near new extruder
-               *    5. engage magnetic field for new extruder
-               *    6. move to parking incl. offset of new extruder
-               *    7. lower Z-Axis
+               *    1. Raise Z-Axis to give enough clearance
+               *    2. Move to park position of old extruder
+               *    3. Disengage magnetic field, wait for delay
+               *    4. Move near new extruder
+               *    5. Engage magnetic field for new extruder
+               *    6. Move to parking incl. offset of new extruder
+               *    7. Lower Z-Axis
                */
 
               // STEP 1
@@ -464,7 +464,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
 
             #if ENABLED(MESH_BED_LEVELING)
 
-              if (leveling_is_active()) {
+              if (planner.leveling_active) {
                 #if ENABLED(DEBUG_LEVELING_FEATURE)
                   if (DEBUGGING(LEVELING)) SERIAL_ECHOPAIR("Z before MBL: ", current_position[Z_AXIS]);
                 #endif