diff --git a/CHANGELOG.md b/CHANGELOG.md
index 066e6266..1942eab4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,10 @@ written while it was being built. See [RELEASING.md](RELEASING.md).
### Added
+- Manage Teams makes unsaved changes hard to lose: a bar at the top stays in
+ view while you scroll and shows what is unsaved with Save and Discard, the
+ people and teams that changed are marked until saved, and following a link
+ away from the page asks first.
- Manage Teams fixes the teams once a team has a submission or teams are
published: a notice says why, and uploading, adding and deleting teams are
disabled. People can still be moved between teams or to Unassigned by hand,
diff --git a/components/frontend/src/lib/components/layout/ConfirmDialog.svelte b/components/frontend/src/lib/components/layout/ConfirmDialog.svelte
new file mode 100644
index 00000000..5138ca89
--- /dev/null
+++ b/components/frontend/src/lib/components/layout/ConfirmDialog.svelte
@@ -0,0 +1,73 @@
+
+
+
+
+
diff --git a/components/frontend/src/routes/(app)/my/hackathon/[id]/teams/manage/+page.svelte b/components/frontend/src/routes/(app)/my/hackathon/[id]/teams/manage/+page.svelte
index a48e1635..191a56e2 100644
--- a/components/frontend/src/routes/(app)/my/hackathon/[id]/teams/manage/+page.svelte
+++ b/components/frontend/src/routes/(app)/my/hackathon/[id]/teams/manage/+page.svelte
@@ -1,5 +1,6 @@
+
+
{#snippet personRow(
person: Person,
from: string,
@@ -599,14 +665,20 @@
)}
{@const matches = projectId !== null && person.preferredProjectIds.includes(projectId)}
{@const answers = answersFor(person)}
+ {@const unsaved = changes.movedIds.has(person.id)}
+