diff --git a/src/components/stock-orders/quick-draft-modal.test.tsx b/src/components/stock-orders/quick-draft-modal.test.tsx
new file mode 100644
index 0000000..d0af3a1
--- /dev/null
+++ b/src/components/stock-orders/quick-draft-modal.test.tsx
@@ -0,0 +1,55 @@
+import { describe, it, expect, beforeEach, vi } from "vitest";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { QuickDraftModal } from "./quick-draft-modal";
+
+// The modal uses ModalShell.Dialog which depends on @base-ui/react.
+// The component test environment stubs it via a passthrough wrapper.
+vi.mock("@/components/ui/modal-shell", () => ({
+ ModalShell: {
+ Dialog: ({ children, open }: { children: React.ReactNode; open: boolean }) =>
+ open ?
{children}
: null,
+ Header: ({ children }: { children: React.ReactNode }) => {children}
,
+ Body: ({ children }: { children: React.ReactNode }) => {children}
,
+ Footer: ({ children }: { children: React.ReactNode }) => {children}
,
+ },
+}));
+
+beforeEach(() => {
+ vi.restoreAllMocks();
+});
+
+describe("QuickDraftModal — header", () => {
+ it("renders nothing when closed", () => {
+ render(
+ {}}
+ />,
+ );
+ expect(screen.queryByTestId("modal")).toBeNull();
+ });
+
+ it("renders the Stock Order Reference input with a default month label", () => {
+ render(
+ {}} />,
+ );
+ const input = screen.getByTestId("stock-order-reference");
+ expect(input).toBeInTheDocument();
+ // Value defaults to "Stock order entry — " (e.g. "Stock order entry — Jul 2026").
+ expect((input as HTMLInputElement).value).toMatch(/^Stock order entry — /);
+ });
+
+ it("lets the buyer rename the reference", async () => {
+ const user = userEvent.setup();
+ render(
+ {}} />,
+ );
+ const input = screen.getByTestId(
+ "stock-order-reference",
+ ) as HTMLInputElement;
+ await user.clear(input);
+ await user.type(input, "Jul 2026 run");
+ expect(input.value).toBe("Jul 2026 run");
+ });
+});
\ No newline at end of file
diff --git a/src/components/stock-orders/quick-draft-modal.tsx b/src/components/stock-orders/quick-draft-modal.tsx
new file mode 100644
index 0000000..4f97583
--- /dev/null
+++ b/src/components/stock-orders/quick-draft-modal.tsx
@@ -0,0 +1,66 @@
+"use client";
+
+import { useMemo } from "react";
+import { Input } from "@/components/ui/input";
+import { ModalShell } from "@/components/ui/modal-shell";
+
+/**
+ * Quick-Draft Modal — item-first stock-order entry on /stock-orders.
+ *
+ * See docs/superpowers/specs/2026-07-30-stock-quick-draft-design.md
+ * for the full design. This file is the modal in its entirety; the
+ * three regions (search, cards, footer) live in sub-components
+ * further down so the test surface stays manageable.
+ *
+ * Data flow:
+ * - search & history hit /api/v1/stock-quick-draft/{search,supplier-history}
+ * - "Add & next" hits /api/v1/stock-quick-draft/add-line
+ * - cards region deletes via /api/v1/stock-quick-draft/line/[lineId]
+ *
+ * ModalShell in this codebase uses a prop-based pattern (eyebrow /
+ * title / description / children / footer) rather than exposing
+ * Header / Body / Footer sub-components, so the input lives as a
+ * child at the top of the dialog. The eyebrow surfaces the
+ * "Stock Order Reference" label above the input in production.
+ */
+
+export interface QuickDraftModalProps {
+ open: boolean;
+ onOpenChange: (next: boolean) => void;
+}
+
+function formatMonthYear(date: Date): string {
+ return date.toLocaleDateString("en-US", { month: "short", year: "numeric" });
+}
+
+export function QuickDraftModal({ open, onOpenChange }: QuickDraftModalProps) {
+ const defaultReference = useMemo(
+ () => `Stock order entry — ${formatMonthYear(new Date())}`,
+ // intentionally only computed once per mount
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [],
+ );
+
+ return (
+ }
+ >
+
+
+
+
+ {/* Regions wired up in later tasks */}
+
+
+
+ );
+}
\ No newline at end of file