diff --git a/frontend/src/components/simulator/SimulatorCanvas.tsx b/frontend/src/components/simulator/SimulatorCanvas.tsx
index b470a94e..c952d129 100644
--- a/frontend/src/components/simulator/SimulatorCanvas.tsx
+++ b/frontend/src/components/simulator/SimulatorCanvas.tsx
@@ -2854,10 +2854,12 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
{/* WiFi status indicator + IoT-gateway launcher (ESP32 + Pico W).
- Renders from the moment a radio-capable board is active —
- before a Run it shows as disconnected, so the icon is a
- stable place to click (the overlay hangs its panel off it). */}
+ Wokwi-style lifecycle: nothing until Run. The badge appears
+ with the simulation (gray while the stack boots, green on
+ got_ip) and leaves on Stop. The overlay hangs its WiFi
+ panel off it while it is up. */}
{activeBoard &&
+ activeBoard.running &&
(isEsp32Kind(activeBoard.boardKind) || activeBoard.boardKind === 'pi-pico-w') &&
(() => {
// The Pico W virtual net assigns its IP deterministically when
diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts
index 2325f952..9902090b 100644
--- a/frontend/src/store/useSimulatorStore.ts
+++ b/frontend/src/store/useSimulatorStore.ts
@@ -2340,6 +2340,18 @@ export const useSimulatorStore = create((set, get) => {
const board = get().boards.find((b) => b.id === boardId);
if (!board) return;
+ // A fresh run starts with a clean radio state. The WiFi/BLE badges are
+ // only visible while the board runs, and nothing else clears them, so
+ // without this a re-run opens showing the PREVIOUS run's association
+ // (a green got_ip badge for a connection nothing has made yet).
+ if (board.wifiStatus || board.bleStatus) {
+ set((s) => ({
+ boards: s.boards.map((b) =>
+ b.id === boardId ? { ...b, wifiStatus: undefined, bleStatus: undefined } : b,
+ ),
+ }));
+ }
+
// Pro gate (run backstop): catches STM32/Pi boards that entered the
// canvas via an example or a loaded project (which bypass the picker's
// add gate). Non-paid web users get the upgrade prompt instead of a run.