diff --git a/.cursor/rules/alerts.mdc b/.cursor/rules/alerts.mdc
new file mode 100644
index 0000000..dfd2dc5
--- /dev/null
+++ b/.cursor/rules/alerts.mdc
@@ -0,0 +1,48 @@
+---
+description: Unified Alert (toast/banner) for app notifications — Figma + drift prevention
+globs: app/**/*.tsx, stories/modals/Alert.stories.js, tests/components/Alert.test.tsx
+alwaysApply: false
+---
+
+# Alerts and notifications
+
+## Source of truth
+
+- **Figma:** [Community Rule System — Modal / Alert](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=6351-14646) (node **6351-14646**).
+- **Code:** `app/components/modals/Alert` — default export `Alert` from `Alert.container.tsx` (Figma docstring on the container).
+
+## When to use `Alert`
+
+Use **`Alert`** for **app-level, section-level, and shell-level** success, warning, error, and neutral status messages that should read as a designed system surface (not body copy alone).
+
+Do **not** recreate the same job with ad-hoc UI: bordered `
`, free-standing `role="alert"` blocks, or raw `text-[var(--color-border-default-utility-negative)]` paragraphs for product messaging.
+
+## Props (lowercase in code; match Figma intent)
+
+| Concern | Prop | Notes |
+| --- | --- | --- |
+| Layout | `type` | `toast` — bottom accent bar, top rounded corners; `banner` — full rounded block, inline or stacked. |
+| Intent | `status` | `default` \| `positive` \| `warning` \| `danger`. |
+| Density | `size` | `s` \| `m` (Figma S/M). Typography and padding are implemented inside `Alert.container.tsx` — do not fork spacing per call site. |
+| Copy | `title`, `description?` | Required title; optional description when `hasBodyText` is true. |
+| Icon | `hasLeadingIcon?` | Default `true`. |
+| Body | `hasBodyText?` | Default `true`; set `false` for title-only. |
+| Dismiss | `onClose?`, `hasTrailingIcon?` | Close control shows only when `onClose` is provided **and** `hasTrailingIcon` is not `false`. Omit `onClose` for non-dismissible messages. |
+
+Valid enum slices for Storybook / guards: `ALERT_*_OPTIONS` in `lib/propNormalization.ts`.
+
+## Choosing toast vs banner
+
+- **`toast`** — transient edge / bottom emphasis (e.g. completed flow), strong bottom border accent.
+- **`banner`** — rounded block; for **page / shell / modal** messaging, mount inside a **`fixed`** (or equivalent) overlay wrapper with `pointer-events-none` on the outer layer and `pointer-events-auto` on the alert so layout chrome does not reflow when the message appears (see `CreateFlowLayoutClient` `topBanners`, profile overlays, `LoginForm`, `PostLoginDraftTransfer`).
+
+## Exemptions (do not force `Alert`)
+
+1. **Single-field validation** under a control — keep `TextInput` / `TextArea` `error` and helper text (e.g. invalid email on the login form) unless design explicitly moves that line into `Alert`.
+2. **Marketing layout** — `HeroBanner`, `ContentBanner` are not system alerts.
+3. **Landmarks** — `role="banner"` on headers/nav is not the `Alert` “banner” type.
+4. **A11y-only live regions** — e.g. tooltip / incrementer `aria-live` for widget state, not product notifications.
+
+## Copy
+
+All user-visible strings go through **`messages/`** and `useTranslation` / message modules per `localization.mdc`.
diff --git a/AGENTS.md b/AGENTS.md
index c750780..5c26812 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -15,6 +15,7 @@ Single-locale (English) today; designed for i18n via `messages/`.
| If you're touching… | Load this rule |
| --- | --- |
| `app/components/**` | `component-structure.mdc`, `component-props.mdc`, `tailwind-styling.mdc` |
+| `Alert`, or user-visible notifications / shell errors / success banners | `alerts.mdc` (and `localization.mdc` for copy) |
| `app/(app)/create/**` | `create-flow.mdc` (+ component rules) |
| `app/api/**` | `api-routes.mdc` |
| `app/hooks/**` | `hooks.mdc` |
diff --git a/app/(app)/create/PostLoginDraftTransfer.tsx b/app/(app)/create/PostLoginDraftTransfer.tsx
index bf56460..178469e 100644
--- a/app/(app)/create/PostLoginDraftTransfer.tsx
+++ b/app/(app)/create/PostLoginDraftTransfer.tsx
@@ -11,6 +11,7 @@ import { useCreateFlow } from "./context/CreateFlowContext";
import { parseCreateFlowScreenFromPathname } from "./utils/flowSteps";
import { saveDraftToServer } from "../../../lib/create/api";
import messages from "../../../messages/en/index";
+import Alert from "../../components/modals/Alert";
const SYNC_ENABLED = process.env.NEXT_PUBLIC_ENABLE_BACKEND_SYNC === "true";
@@ -139,12 +140,27 @@ export function PostLoginDraftTransfer({
if (!transferError) return null;
+ const [titleLine, ...rest] = transferError.split(/\n\n+/);
+ const title = (titleLine ?? transferError).trim();
+ const description = rest.join("\n\n").trim() || undefined;
+
return (
-