diff --git a/src/sxwm.c b/src/sxwm.c
index 55fe97b..9c1b2ae 100644
--- a/src/sxwm.c
+++ b/src/sxwm.c
@@ -3077,6 +3151,48 @@ void update_mons(void)
 	}
 
 	free(old);
+
+	/*
+	 client->mon is a plain index into mons[], but monitor count/order
+	 can change across a hotplug (e.g. the internal panel toggled off
+	 for a closed lid, then back on). A stale index gets silently
+	 reinterpreted as whatever monitor now sits at that slot, dragging
+	 windows onto the wrong screen -- or, once clamped, squeezing them
+	 into bounds far smaller than they were tiled for. Re-derive mon
+	 from each client's real last-known position instead of trusting
+	 the old index, and pull floating windows back on-screen if the
+	 monitor they end up on no longer covers where they were sitting.
+	 */
+	for (int ws = 0; ws < NUM_WORKSPACES; ws++) {
+		for (Client *c = workspaces[ws]; c; c = c->next) {
+			c->mon = CLAMP(get_monitor_for(c), 0, n_mons - 1);
+
+			if (!c->floating)
+				continue;
+
+			int mx = mons[c->mon].x, my = mons[c->mon].y;
+			int mw = mons[c->mon].w, mh = mons[c->mon].h;
+			int x = c->x, y = c->y;
+
+			if (x < mx)
+				x = mx;
+			if (y < my)
+				y = my;
+			if (x + c->w > mx + mw)
+				x = mx + mw - c->w;
+			if (y + c->h > my + mh)
+				y = my + mh - c->h;
+
+			if (x != c->x || y != c->y) {
+				c->x = x;
+				c->y = y;
+				if (c->mapped)
+					XMoveWindow(dpy, c->win, x, y);
+			}
+		}
+	}
+
+	current_mon = CLAMP(current_mon, 0, n_mons - 1);
 }
 
 void update_net_client_list(void)
