diff --git a/.changeset/FN-7837-card-size-badge-alignment.md b/.changeset/FN-7837-card-size-badge-alignment.md
new file mode 100644
index 0000000000..2a26f43d27
--- /dev/null
+++ b/.changeset/FN-7837-card-size-badge-alignment.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Task card size badge (S/M/L) no longer drops onto a misaligned second row on cards with extra badges.
+category: fix
+dev: Groups the wrapping header status/meta badges in TaskCard so `.card-id` and the right-aligned `.card-header-actions` (holding `.card-size-badge`) stay on the top row; fixes the fast-mode (`.card-execution-mode-badge`) orphaned-size-chip case (FN-7832 repro).
diff --git a/packages/dashboard/app/components/TaskCard.css b/packages/dashboard/app/components/TaskCard.css
index e7e952bcca..64680b513d 100644
--- a/packages/dashboard/app/components/TaskCard.css
+++ b/packages/dashboard/app/components/TaskCard.css
@@ -96,14 +96,32 @@ Mobile long-press opens the Board task context menu, so non-editing card text mu
.card-header {
display: flex;
- align-items: center;
- flex-wrap: wrap;
+ align-items: flex-start;
+ flex-wrap: nowrap;
gap: var(--space-xs);
row-gap: var(--space-xs);
min-width: 0;
margin-bottom: var(--space-xs);
}
+/*
+FNXC:TaskCardLayout 2026-07-11-00:00:
+FN-7837 keeps the id row and right-aligned size/actions cluster together while extra header badges wrap inside this middle group, preventing the size chip from orphaning onto a misaligned second row on desktop and mobile.
+*/
+.card-header-badges {
+ display: flex;
+ align-items: center;
+ flex: 1 1 auto;
+ flex-wrap: wrap;
+ gap: var(--space-xs);
+ row-gap: var(--space-xs);
+ min-width: 0;
+}
+
+.card-id {
+ flex-shrink: 0;
+}
+
.card-meta-badges {
display: flex;
align-items: center;
@@ -1408,7 +1426,9 @@ executing. These map 1:1 to the unified progress status so the dot color encodes
.card-header-actions {
display: flex;
align-items: center;
- gap: 6px;
+ align-self: flex-start;
+ flex: 0 0 auto;
+ gap: var(--space-xs);
margin-left: auto;
}
@@ -1773,9 +1793,9 @@ too so future divergence doesn't have to rediscover the shared selector group.
height: 16px;
}
- /* FN-4365/FN-4351: keep secondary actions compact and inline with the header title row on mobile. */
+ /* FN-4365/FN-4351/FN-7837: keep secondary actions compact, token-spaced, and inline with the non-wrapping header title row on mobile. */
.card-header-actions {
- gap: 4px;
+ gap: calc(var(--space-xs) / 2);
flex-shrink: 0;
}
@@ -1835,6 +1855,7 @@ too so future divergence doesn't have to rediscover the shared selector group.
}
+ .card-header-badges,
.card-meta-badges {
gap: calc(var(--space-xs) / 2);
row-gap: var(--space-xs);
diff --git a/packages/dashboard/app/components/TaskCard.tsx b/packages/dashboard/app/components/TaskCard.tsx
index 5ca8af1df1..1b0a93482c 100644
--- a/packages/dashboard/app/components/TaskCard.tsx
+++ b/packages/dashboard/app/components/TaskCard.tsx
@@ -2757,6 +2757,34 @@ function TaskCardComponent({
// metadata (absent for the common "off" default) — include it in the wrapper
// guard so `.card-meta-badges` only renders when it has a real child.
|| showOversightBadge;
+ const hasHeaderBadges = Boolean(isPaused)
+ || Boolean(!isPaused && visualStatus && visualStatus !== "queued")
+ || planReviewRunning
+ || Boolean(!isPaused && task.column === "todo" && !visualStatus && (task.steps?.length ?? 0) > 0)
+ || Boolean(hasInReviewStall && stallCopy)
+ || cliWaitingOnInput
+ || cliNeedsAttention
+ || Boolean(hasStalePausedReview && stalePausedReviewCopy)
+ || Boolean(hasTaskAgeStaleness && taskAgeStalenessCopy)
+ || Boolean(isStuck && (isPaused || !task.status || task.status === "queued"))
+ || Boolean(Array.isArray((task as TaskWithBranchProgress).branchProgress) && (task as TaskWithBranchProgress).branchProgress!.length > 0)
+ || Boolean(task.plannerOverseerState && task.plannerOverseerState.state !== "idle")
+ || Boolean(showStalledReview && stalledReview)
+ || Boolean(livePrInfo || liveIssueInfo)
+ || Boolean(task.gitlabTracking?.item)
+ || Boolean(prNode)
+ || hasCardMetaBadges
+ || task.noCommitsExpected === true
+ || Boolean(task.missionId);
+ const hasHeaderActions = Boolean(isAwaitingInput && onOpenDetailWithTab)
+ || Boolean(canEdit)
+ || Boolean(task.column === "triage" && onDeleteTask)
+ || Boolean(task.column === "done" && onArchiveTask)
+ || Boolean(task.column === "archived" && onUnarchiveTask)
+ || Boolean((task.column === "done" || task.column === "archived") && onRevertTask && isRevertable)
+ || Boolean(task.column === "in-progress" && onMoveTask)
+ || Boolean(task.size)
+ || hasContextMenuActions;
if (isEditing) {
return (
@@ -2834,6 +2862,12 @@ function TaskCardComponent({
)}
{task.id}
+ {hasHeaderBadges && (
+ /*
+ FNXC:TaskCardLayout 2026-07-11-00:00:
+ FN-7837 keeps the task id and right-aligned size/actions cluster in the same non-wrapping header row. Extra header badges (fast-mode, priority, oversight, decision-only, PR/GitHub, and status chips) wrap inside this middle group instead of pushing the size chip onto a misaligned second row on desktop or mobile.
+ */
+