diff --git a/components/composer-actions.tsx b/components/composer-actions.tsx
new file mode 100644
index 0000000..f2be32a
--- /dev/null
+++ b/components/composer-actions.tsx
@@ -0,0 +1,56 @@
+"use client";
+
+import type { ReactNode } from "react";
+import { DumbbellIcon } from "lucide-react";
+
+/** Home and the draft share one wrapping action row. Picker controls lead;
+ * setup is centered only when it is the sole action. */
+export function ComposerActions({ picker, setup }: { picker?: ReactNode; setup?: ReactNode }) {
+ if (!picker && !setup) return null;
+ return (
+
+ {picker}
+ {setup}
+
+ );
+}
+
+/** Count and Clear stay together if the setup action wraps onto another line.
+ * These are node counts, even when a whole chain supplied the selection. */
+export function NodePickerControl({ count, onOpen, onClear }: {
+ count: number;
+ onOpen?: () => void;
+ onClear?: () => void;
+}) {
+ return (
+
+
+ {count > 0 && (
+
+ )}
+
+ );
+}
diff --git a/components/home.tsx b/components/home.tsx
index 5c674a6..4b16d62 100644
--- a/components/home.tsx
+++ b/components/home.tsx
@@ -6,6 +6,7 @@ import { CornerDownLeftIcon, DumbbellIcon } from "lucide-react";
import { GraphView } from "@/components/graph-view";
import { MinimalHome } from "@/components/minimal-home";
import { SetupDialog } from "@/components/setup-dialog";
+import { ComposerActions, NodePickerControl } from "@/components/composer-actions";
import { useStrongKeyless, useZeroKeys, ZeroKeysPill } from "@/components/setup-cta";
import { DictationBar, joinDictation, useDictation } from "@/components/dictation";
import { useFieldCycle } from "@/components/field-cycle";
@@ -217,43 +218,18 @@ export function Home({
send consumes it). Practice mode with nothing picked
shows the pick HINT so the affordance is discoverable;
teaching mode with nothing picked renders nothing. */}
- {(practiceProps.length > 0 || mode === "practice") && (
-