diff --git a/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.spec.ts b/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.spec.ts
new file mode 100644
--- /dev/null
+++ b/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.spec.ts
@@ -0,0 +1,194 @@
+import { act, cleanup, renderHook } from "@testing-library/react";
+import {
+  afterEach,
+  beforeEach,
+  describe,
+  expect,
+  it,
+  vi,
+  type Mock,
+} from "vitest";
+import type { MoodboardPersistenceAdapter } from "../adapter";
+
+const TOMBSTONE_STORAGE_KEY = "artcraft_moodboard_deleted_tokens_v1";
+
+describe("moodboard deletion during a save", () => {
+  let sync: typeof import("./moodboardSync");
+  let library: typeof import("../boards/BoardLibraryStore").useBoardLibraryStore;
+  let persistence: MoodboardPersistenceAdapter;
+  let removeRemote: Mock<(token: string) => Promise<boolean>>;
+  let finishSave: (result: { success: boolean; token?: string }) => void;
+  let pageHideListeners: EventListener[];
+
+  beforeEach(async () => {
+    vi.resetModules();
+    vi.useFakeTimers();
+    localStorage.clear();
+    pageHideListeners = [];
+    const addEventListener = window.addEventListener.bind(window);
+    vi.spyOn(window, "addEventListener").mockImplementation(
+      (type, listener, options) => {
+        if (type === "pagehide")
+          pageHideListeners.push(listener as EventListener);
+        addEventListener(type, listener, options);
+      },
+    );
+    vi.spyOn(console, "error").mockImplementation(() => undefined);
+    sync = await import("./moodboardSync");
+    library = (await import("../boards/BoardLibraryStore"))
+      .useBoardLibraryStore;
+    removeRemote = vi.fn().mockResolvedValue(true);
+    persistence = {
+      getUserId: () => "user-1",
+      listBoards: vi.fn().mockResolvedValue({ success: true, boards: [] }),
+      loadBoard: vi.fn(),
+      saveBoard: vi.fn().mockImplementation(
+        () =>
+          new Promise((resolve) => {
+            finishSave = resolve;
+          }),
+      ),
+      deleteBoard: removeRemote,
+    };
+  });
+
+  afterEach(() => {
+    cleanup();
+    for (const listener of pageHideListeners) {
+      window.removeEventListener("pagehide", listener);
+    }
+    vi.clearAllTimers();
+    vi.useRealTimers();
+    vi.restoreAllMocks();
+  });
+
+  it("deletes the remote row created after its local board was deleted", async () => {
+    const boardId = await startSave();
+
+    await act(async () => {
+      await sync.deleteBoardEverywhere(boardId);
+    });
+    expect(persistence.deleteBoard).not.toHaveBeenCalled();
+    await act(async () => {
+      finishSave({ success: true, token: "remote-1" });
+    });
+
+    expect(library.getState().boards[boardId]).toBeUndefined();
+    expect(persistence.deleteBoard).toHaveBeenCalledExactlyOnceWith("remote-1");
+    expect(readTombstones()).toEqual([]);
+  });
+
+  it.each(["failure", "rejection", "unsupported"])(
+    "keeps a durable tombstone when remote deletion ends in %s",
+    async (outcome) => {
+      if (outcome === "failure") removeRemote.mockResolvedValue(false);
+      if (outcome === "rejection")
+        removeRemote.mockRejectedValue(new Error("offline"));
+      if (outcome === "unsupported") persistence.deleteBoard = undefined;
+      const boardId = await startSave();
+
+      await act(async () => {
+        await sync.deleteBoardEverywhere(boardId);
+      });
+      await act(async () => {
+        finishSave({ success: true, token: "remote-1" });
+      });
+
+      expect(library.getState().boards[boardId]).toBeUndefined();
+      expect(readTombstones()).toEqual(["remote-1"]);
+    },
+  );
+
+  it("does not delete a board that still exists when its save completes", async () => {
+    const boardId = await startSave();
+
+    await act(async () => {
+      finishSave({ success: true, token: "remote-1" });
+    });
+
+    expect(library.getState().boards[boardId].remoteToken).toBe("remote-1");
+    expect(library.getState().boards[boardId].needsSync).toBe(false);
+    expect(persistence.deleteBoard).not.toHaveBeenCalled();
+    expect(readTombstones()).toEqual([]);
+  });
+
+  it("repeats deletion if an update finishes after a linked board was deleted", async () => {
+    const boardId = await startSave("existing-remote");
+
+    await act(async () => {
+      await sync.deleteBoardEverywhere(boardId);
+    });
+    expect(persistence.deleteBoard).toHaveBeenCalledExactlyOnceWith(
+      "existing-remote",
+    );
+    // Updates need not return a token; the original board already has it.
+    await act(async () => {
+      finishSave({ success: true });
+    });
+
+    expect(persistence.deleteBoard).toHaveBeenCalledTimes(2);
+    expect(persistence.deleteBoard).toHaveBeenLastCalledWith("existing-remote");
+    expect(readTombstones()).toEqual([]);
+  });
+
+  it.each([true, false])(
+    "does not restore a tombstoned board from the pre-delete listing (retry succeeds: %s)",
+    async (deleted) => {
+      localStorage.setItem(TOMBSTONE_STORAGE_KEY, JSON.stringify(["remote-1"]));
+      vi.mocked(persistence.listBoards).mockResolvedValue({
+        success: true,
+        boards: [
+          {
+            token: "remote-1",
+            name: "Deleted board",
+            updatedAt: "2026-10-19T00:00:00Z",
+          },
+        ],
+      });
+      removeRemote.mockResolvedValue(deleted);
+      vi.mocked(persistence.loadBoard).mockResolvedValue({
+        success: true,
+        documentJson: JSON.stringify({
+          version: 1,
+          board: { name: "Deleted board" },
+        }),
+      });
+
+      renderHook(() =>
+        sync.useMoodboardSync({
+          sendToGeneration: () => undefined,
+          persistence,
+        }),
+      );
+      await act(async () => undefined);
+
+      expect(persistence.deleteBoard).toHaveBeenCalledExactlyOnceWith(
+        "remote-1",
+      );
+      expect(persistence.loadBoard).not.toHaveBeenCalled();
+      expect(library.getState().boardOrder).toEqual([]);
+      expect(readTombstones()).toEqual(deleted ? [] : ["remote-1"]);
+    },
+  );
+
+  async function startSave(remoteToken?: string): Promise<string> {
+    const boardId = library.getState().createBoard("Draft");
+    if (remoteToken)
+      library.getState().setBoardRemoteToken(boardId, remoteToken);
+    const hook = renderHook(() =>
+      sync.useMoodboardSync({
+        sendToGeneration: () => undefined,
+        persistence,
+      }),
+    );
+    // Finish the initial empty remote listing before starting a manual save.
+    await act(async () => undefined);
+    act(() => hook.result.current.saveNow());
+    expect(persistence.saveBoard).toHaveBeenCalledTimes(1);
+    return boardId;
+  }
+
+  function readTombstones(): string[] {
+    return JSON.parse(localStorage.getItem(TOMBSTONE_STORAGE_KEY) ?? "[]");
+  }
+});
diff --git a/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.ts b/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.ts
--- a/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.ts
+++ b/frontend/libs/components/moodboard/src/lib/persistence/moodboardSync.ts
@@ -3,10 +3,7 @@ import { create } from "zustand";
 import { useBoardLibraryStore } from "../boards/BoardLibraryStore";
 import type { Board } from "../boards/boardTypes";
 import { useMoodboardStore } from "../canvas/MoodboardStore";
-import type {
-  MoodboardAdapter,
-  MoodboardPersistenceAdapter,
-} from "../adapter";
+import type { MoodboardAdapter, MoodboardPersistenceAdapter } from "../adapter";
 import {
   applyResolvedMediaUrls,
   collectUnresolvedMediaTokens,
@@ -211,14 +208,7 @@ export async function deleteBoardEverywhere(boardId: string): Promise<void> {
   if (!token) return;
 
   addTombstone(token);
-  if (persistenceRef?.deleteBoard) {
-    try {
-      const deleted = await persistenceRef.deleteBoard(token);
-      if (deleted) removeTombstone(token);
-    } catch (error) {
-      console.error("[Moodboard] remote board delete failed:", error);
-    }
-  }
+  await deleteRemoteBoard(persistenceRef, token);
 }
 
 // ---------- dirty tracking + scheduling ----------
@@ -387,6 +377,17 @@ async function saveBoard(
       console.error("[Moodboard] board save failed:", result.errorMessage);
       return false;
     }
+    // Deletion may have happened before a newly created board received its
+    // token. Compensate for the completed write instead of leaving an orphan
+    // that the next hydration would restore. Updates can race deletion too.
+    if (!useBoardLibraryStore.getState().boards[boardId]) {
+      const token = result.token ?? board.remoteToken;
+      if (token) {
+        addTombstone(token);
+        await deleteRemoteBoard(persistence, token);
+      }
+      return true;
+    }
     withDirtySuppressed(() => {
       const store = useBoardLibraryStore.getState();
       if (result.token && !board.remoteToken) {
@@ -436,8 +437,11 @@ async function hydrateRemoteBoards(
     if (syncUserId !== userId) return;
 
     if (listed.success && listed.boards) {
-      await retryTombstonedDeletes(persistence);
+      // A successful retry removes its tombstone, but the listing above was
+      // fetched before that deletion and can still contain the deleted row.
       const tombstones = readTombstones();
+      await retryTombstonedDeletes(persistence);
+      readTombstones().forEach((token) => tombstones.add(token));
       const rows = listed.boards.filter((row) => !tombstones.has(row.token));
 
       // Each board hydrates independently — one bad row/fetch must not
@@ -595,6 +599,19 @@ function removeTombstone(token: string): void {
   writeTombstones(tokens);
 }
 
+async function deleteRemoteBoard(
+  persistence: MoodboardPersistenceAdapter | null,
+  token: string,
+): Promise<void> {
+  if (!persistence?.deleteBoard) return;
+  try {
+    const deleted = await persistence.deleteBoard(token);
+    if (deleted) removeTombstone(token);
+  } catch (error) {
+    console.error("[Moodboard] remote board delete failed:", error);
+  }
+}
+
 async function retryTombstonedDeletes(
   persistence: MoodboardPersistenceAdapter,
 ): Promise<void> {
