From 35f8d58c653e71b096ff9b25a615f59d4afb1566 Mon Sep 17 00:00:00 2001
From: Thomas Petersen <thomasp@squareup.com>
Date: Thu, 14 May 2026 20:42:52 -0400
Subject: [PATCH 1/5] fix(ui): expand content width and align message metadata

Co-authored-by: Cursor <cursoragent@cursor.com>
---
 .../src/features/channels/ui/ChannelPane.tsx  |   2 +-
 .../src/features/messages/ui/DayDivider.tsx   |   2 +-
 .../features/messages/ui/MessageComposer.tsx  |   2 +-
 .../src/features/messages/ui/MessageRow.tsx   | 129 +++++++-------
 .../features/messages/ui/MessageTimeline.tsx  |   2 +-
 .../features/messages/ui/MessageTimestamp.tsx |   4 +-
 .../features/messages/ui/SystemMessageRow.tsx | 161 +++++++++---------
 .../messages/ui/TypingIndicatorRow.tsx        |   1 -
 desktop/src/shared/ui/ViewLoadingFallback.tsx |   4 +-
 web/src/features/repos/ui/RepoDetailPage.tsx  |   6 +-
 web/src/features/repos/ui/ReposPage.tsx       |   4 +-
 11 files changed, 164 insertions(+), 153 deletions(-)

diff --git a/desktop/src/features/channels/ui/ChannelPane.tsx b/desktop/src/features/channels/ui/ChannelPane.tsx
index 93060be3a3..90dd441cd3 100644
--- a/desktop/src/features/channels/ui/ChannelPane.tsx
+++ b/desktop/src/features/channels/ui/ChannelPane.tsx
@@ -401,7 +401,7 @@ export const ChannelPane = React.memo(function ChannelPane({
                 showTopBorder={false}
               />
               <div className="h-7 bg-background px-4 pb-1 pt-0 sm:px-6 -mt-1">
-                <div className="mx-auto flex h-full w-full max-w-4xl items-center gap-2">
+                <div className="flex h-full w-full items-center gap-2">
                   {hasComposerBotActivity ? (
                     <div className="shrink-0">
                       <BotActivityComposerAction
diff --git a/desktop/src/features/messages/ui/DayDivider.tsx b/desktop/src/features/messages/ui/DayDivider.tsx
index 5d7ec83498..4daaae12da 100644
--- a/desktop/src/features/messages/ui/DayDivider.tsx
+++ b/desktop/src/features/messages/ui/DayDivider.tsx
@@ -2,7 +2,7 @@ export function DayDivider({ label }: { label: string }) {
   return (
     <section
       aria-label={label}
-      className="sticky top-11 z-20 flex justify-center py-1"
+      className="sticky top-11 z-[5] flex justify-center py-1"
       data-testid="message-timeline-day-divider"
       data-day-label={label}
     >
diff --git a/desktop/src/features/messages/ui/MessageComposer.tsx b/desktop/src/features/messages/ui/MessageComposer.tsx
index 0f870985c1..9e08ff4be4 100644
--- a/desktop/src/features/messages/ui/MessageComposer.tsx
+++ b/desktop/src/features/messages/ui/MessageComposer.tsx
@@ -555,7 +555,7 @@ export function MessageComposer({
         aria-hidden="true"
         className="absolute inset-x-0 bottom-0 h-5 bg-background"
       />
-      <div className="relative mx-auto flex w-full max-w-4xl flex-col gap-3">
+      <div className="relative flex w-full flex-col gap-3">
         <form
           className="relative isolate rounded-2xl border border-border/50 bg-background/70 px-3 pb-2 pt-3 shadow-[0_4px_24px_rgba(0,0,0,0.08)] backdrop-blur-xl supports-[backdrop-filter]:bg-background/55 dark:shadow-[0_4px_24px_rgba(0,0,0,0.35)] sm:px-4"
           data-testid="message-composer"
diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx
index 109ec07801..b2728ebf8f 100644
--- a/desktop/src/features/messages/ui/MessageRow.tsx
+++ b/desktop/src/features/messages/ui/MessageRow.tsx
@@ -178,26 +178,28 @@ export const MessageRow = React.memo(
       </h3>
     );
 
-    const metadataNode = (
-      <div className="ml-auto flex items-center gap-2 text-xs text-muted-foreground">
-        <div className="relative">
-          <div className="absolute right-0 top-1/2 -translate-y-1/2">
-            <MessageActionBar
-              activeReplyTargetId={activeReplyTargetId}
-              message={message}
-              onDelete={onDelete}
-              onEdit={onEdit}
-              onMarkUnread={onMarkUnread}
-              onReactionSelect={
-                canToggleReactions ? handleReactionSelect : undefined
-              }
-              onReply={onReply}
-              reactionErrorMessage={reactionErrorMessage}
-              reactionPending={reactionPending}
-              reactions={reactions}
-            />
-          </div>
-        </div>
+    const actionBarNode = (
+      <div className="absolute right-2 top-1 z-10">
+        <MessageActionBar
+          activeReplyTargetId={activeReplyTargetId}
+          message={message}
+          onDelete={onDelete}
+          onEdit={onEdit}
+          onMarkUnread={onMarkUnread}
+          onReactionSelect={
+            canToggleReactions ? handleReactionSelect : undefined
+          }
+          onReply={onReply}
+          reactionErrorMessage={reactionErrorMessage}
+          reactionPending={reactionPending}
+          reactions={reactions}
+        />
+      </div>
+    );
+
+    const inlineMetadataNode = (
+      <div className="flex shrink-0 items-baseline gap-2 text-xs">
+        <MessageTimestamp createdAt={message.createdAt} time={message.time} />
         {message.pending ? (
           <p className="font-medium uppercase tracking-[0.14em] text-primary/80">
             Sending
@@ -211,7 +213,6 @@ export const MessageRow = React.memo(
             <TooltipContent>This message has been edited</TooltipContent>
           </Tooltip>
         ) : null}
-        <MessageTimestamp createdAt={message.createdAt} time={message.time} />
       </div>
     );
 
@@ -281,52 +282,64 @@ export const MessageRow = React.memo(
 
         <article
           className={cn(
-            "group/message rounded-2xl px-2 py-1 transition-colors",
+            "group/message relative rounded-2xl px-2 py-1 transition-colors",
             isThreadReplyLayout ? "space-y-1" : "flex items-start gap-2.5",
             highlighted ? "bg-primary/10 ring-1 ring-primary/30" : "",
           )}
           data-message-id={message.id}
           data-testid="message-row"
         >
+          {actionBarNode}
           {isThreadReplyLayout ? (
-            <>
-              <div className="flex min-w-0 items-start gap-1.5">
-                {message.pubkey ? (
-                  <UserProfilePopover
-                    pubkey={message.pubkey}
-                    role={message.role}
-                    botIdenticonValue={message.author}
+            <div className="flex min-w-0 items-start gap-1.5">
+              {message.pubkey ? (
+                <UserProfilePopover
+                  pubkey={message.pubkey}
+                  role={message.role}
+                  botIdenticonValue={message.author}
+                >
+                  <button
+                    className={cn(
+                      "flex shrink-0 items-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
+                      avatarButtonRadiusClass,
+                    )}
+                    type="button"
                   >
-                    <button
-                      className="flex shrink-0 items-start gap-1.5 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
-                      type="button"
+                    {avatarNode}
+                  </button>
+                </UserProfilePopover>
+              ) : (
+                <div className="flex shrink-0 items-start">{avatarNode}</div>
+              )}
+              <div className="min-w-0 flex-1 space-y-0.5">
+                <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
+                  {message.pubkey ? (
+                    <UserProfilePopover
+                      pubkey={message.pubkey}
+                      role={message.role}
+                      botIdenticonValue={message.author}
                     >
-                      {avatarNode}
-                      {authorNode}
-                    </button>
-                  </UserProfilePopover>
-                ) : (
-                  <>
-                    <div className="flex shrink-0 items-start">
-                      {avatarNode}
-                    </div>
-                    {authorNode}
-                  </>
-                )}
-                <div className="min-w-0 flex-1">
-                  <div className="flex min-w-0 flex-wrap items-start gap-x-2 gap-y-0.5">
-                    {message.personaDisplayName &&
-                    message.personaDisplayName !== message.author ? (
-                      <span className="text-xs text-muted-foreground">
-                        {message.personaDisplayName}
-                      </span>
-                    ) : null}
-                    {metadataNode}
-                  </div>
+                      <button
+                        className="truncate rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
+                        type="button"
+                      >
+                        {authorNode}
+                      </button>
+                    </UserProfilePopover>
+                  ) : (
+                    authorNode
+                  )}
+                  {inlineMetadataNode}
+                  {message.personaDisplayName &&
+                  message.personaDisplayName !== message.author ? (
+                    <span className="text-xs text-muted-foreground">
+                      {message.personaDisplayName}
+                    </span>
+                  ) : null}
                 </div>
+                <div className="min-w-0 space-y-0.5">{messageBodyNode}</div>
               </div>
-              <div className="min-w-0 space-y-0.5">{messageBodyNode}</div>
-            </>
+            </div>
           ) : (
             <>
               {message.pubkey ? (
@@ -349,7 +362,7 @@ export const MessageRow = React.memo(
                 <div className="flex shrink-0 items-start">{avatarNode}</div>
               )}
               <div className="-mt-1 min-w-0 flex-1 space-y-0">
-                <div className="flex min-w-0 flex-wrap items-start gap-x-2 gap-y-0">
+                <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0">
                   {message.pubkey ? (
                     <UserProfilePopover
                       pubkey={message.pubkey}
@@ -366,13 +379,13 @@ export const MessageRow = React.memo(
                   ) : (
                     authorNode
                   )}
+                  {inlineMetadataNode}
                   {message.personaDisplayName &&
                   message.personaDisplayName !== message.author ? (
                     <span className="text-xs text-muted-foreground">
                       {message.personaDisplayName}
                     </span>
                   ) : null}
-                  {metadataNode}
                 </div>
                 <div className="-mt-0.5">{messageBodyNode}</div>
               </div>
diff --git a/desktop/src/features/messages/ui/MessageTimeline.tsx b/desktop/src/features/messages/ui/MessageTimeline.tsx
index 7e223a2555..8f0500ed3b 100644
--- a/desktop/src/features/messages/ui/MessageTimeline.tsx
+++ b/desktop/src/features/messages/ui/MessageTimeline.tsx
@@ -135,7 +135,7 @@ export const MessageTimeline = React.memo(function MessageTimeline({
           ref={scrollContainerRef}
         >
           <div
-            className="mx-auto flex w-full max-w-4xl flex-col gap-2 pb-10 pt-16"
+            className="flex w-full flex-col gap-2 pb-10 pt-16"
             ref={contentRef}
           >
             <div ref={topSentinelRef} aria-hidden className="h-px" />
diff --git a/desktop/src/features/messages/ui/MessageTimestamp.tsx b/desktop/src/features/messages/ui/MessageTimestamp.tsx
index fe6ff873bc..e8285d173f 100644
--- a/desktop/src/features/messages/ui/MessageTimestamp.tsx
+++ b/desktop/src/features/messages/ui/MessageTimestamp.tsx
@@ -11,7 +11,9 @@ export function MessageTimestamp({
   return (
     <Tooltip>
       <TooltipTrigger asChild>
-        <p className="cursor-default whitespace-nowrap">{time}</p>
+        <p className="shrink-0 cursor-default whitespace-nowrap text-xs font-normal leading-none tabular-nums text-muted-foreground/55">
+          {time}
+        </p>
       </TooltipTrigger>
       <TooltipContent side="top">
         {formatFullDateTime(createdAt)}
diff --git a/desktop/src/features/messages/ui/SystemMessageRow.tsx b/desktop/src/features/messages/ui/SystemMessageRow.tsx
index 05fea9bd73..0bd848a68d 100644
--- a/desktop/src/features/messages/ui/SystemMessageRow.tsx
+++ b/desktop/src/features/messages/ui/SystemMessageRow.tsx
@@ -200,7 +200,7 @@ export const SystemMessageRow = React.memo(function SystemMessageRow({
 
   return (
     <div
-      className="group/message rounded-2xl px-2 py-1 transition-colors"
+      className="group/message relative rounded-2xl px-2 py-1 transition-colors"
       data-testid="system-message-row"
     >
       <div className="flex items-start gap-2.5">
@@ -211,9 +211,15 @@ export const SystemMessageRow = React.memo(function SystemMessageRow({
           testId="system-message-avatar"
         />
         <div className="min-w-0 flex-1">
-          <p className="truncate text-sm font-semibold leading-none tracking-tight text-foreground/90">
-            {description.title}
-          </p>
+          <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
+            <p className="truncate text-sm font-semibold leading-none tracking-tight text-foreground/90">
+              {description.title}
+            </p>
+            <MessageTimestamp
+              createdAt={message.createdAt}
+              time={message.time}
+            />
+          </div>
           <p className="mt-1 text-sm leading-snug text-muted-foreground/70">
             {description.action}
           </p>
@@ -235,86 +241,77 @@ export const SystemMessageRow = React.memo(function SystemMessageRow({
             ) : null}
           </div>
         </div>
-        <div className="ml-auto flex items-center gap-1 text-xs text-muted-foreground/60">
-          <div className="relative">
-            <div className="absolute right-0 top-1/2 -translate-y-1/2">
-              {canToggleReactions ? (
-                <div
-                  className={cn(
-                    "overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
-                    "max-w-0 border-0 shadow-none translate-y-1 opacity-0",
-                    "group-hover/message:max-w-9 group-hover/message:border group-hover/message:border-border/70 group-hover/message:shadow-sm group-hover/message:translate-y-0 group-hover/message:opacity-100",
-                    "group-focus-within/message:max-w-9 group-focus-within/message:border group-focus-within/message:border-border/70 group-focus-within/message:shadow-sm group-focus-within/message:translate-y-0 group-focus-within/message:opacity-100",
-                    isReactionPickerOpen
-                      ? "max-w-9 border border-border/70 shadow-sm translate-y-0 opacity-100"
-                      : "",
-                  )}
+        <div className="absolute right-2 top-1 z-10">
+          {canToggleReactions ? (
+            <div
+              className={cn(
+                "overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
+                "max-w-0 border-0 shadow-none translate-y-1 opacity-0",
+                "group-hover/message:max-w-9 group-hover/message:border group-hover/message:border-border/70 group-hover/message:shadow-sm group-hover/message:translate-y-0 group-hover/message:opacity-100",
+                "group-focus-within/message:max-w-9 group-focus-within/message:border group-focus-within/message:border-border/70 group-focus-within/message:shadow-sm group-focus-within/message:translate-y-0 group-focus-within/message:opacity-100",
+                isReactionPickerOpen
+                  ? "max-w-9 border border-border/70 shadow-sm translate-y-0 opacity-100"
+                  : "",
+              )}
+            >
+              <div className="flex items-center gap-1 p-1">
+                <Popover
+                  onOpenChange={setIsReactionPickerOpen}
+                  open={isReactionPickerOpen}
                 >
-                  <div className="flex items-center gap-1 p-1">
-                    <Popover
-                      onOpenChange={setIsReactionPickerOpen}
-                      open={isReactionPickerOpen}
-                    >
-                      <Tooltip>
-                        <TooltipTrigger asChild>
-                          <PopoverTrigger asChild>
-                            <Button
-                              aria-label="Open reactions"
-                              className="h-6 w-6 rounded-full p-0"
-                              disabled={reactionPending}
-                              size="sm"
-                              type="button"
-                              variant={
-                                isReactionPickerOpen ? "secondary" : "ghost"
-                              }
-                            >
-                              {reactionPending ? (
-                                <Spinner className="h-3 w-3" />
-                              ) : (
-                                <SmilePlus className="h-3 w-3" />
-                              )}
-                            </Button>
-                          </PopoverTrigger>
-                        </TooltipTrigger>
-                        <TooltipContent>React</TooltipContent>
-                      </Tooltip>
-                      <PopoverContent
-                        align="end"
-                        className="w-auto p-0 rounded-2xl overflow-hidden border-0 bg-transparent shadow-none"
-                        side="top"
-                        sideOffset={10}
-                      >
-                        {reactionErrorMessage ? (
-                          <div className="px-3 pt-3 pb-0">
-                            <p className="text-xs text-destructive">
-                              {reactionErrorMessage}
-                            </p>
-                          </div>
-                        ) : null}
-                        <Picker
-                          data={data}
-                          onEmojiSelect={(emoji: { native: string }) => {
-                            void handleReactionSelect(emoji.native).finally(
-                              () => {
-                                setIsReactionPickerOpen(false);
-                              },
-                            );
-                          }}
-                          theme="auto"
-                          previewPosition="none"
-                          skinTonePosition="search"
-                          set="native"
-                          maxFrequentRows={2}
-                          perLine={8}
-                        />
-                      </PopoverContent>
-                    </Popover>
-                  </div>
-                </div>
-              ) : null}
+                  <Tooltip>
+                    <TooltipTrigger asChild>
+                      <PopoverTrigger asChild>
+                        <Button
+                          aria-label="Open reactions"
+                          className="h-6 w-6 rounded-full p-0"
+                          disabled={reactionPending}
+                          size="sm"
+                          type="button"
+                          variant={isReactionPickerOpen ? "secondary" : "ghost"}
+                        >
+                          {reactionPending ? (
+                            <Spinner className="h-3 w-3" />
+                          ) : (
+                            <SmilePlus className="h-3 w-3" />
+                          )}
+                        </Button>
+                      </PopoverTrigger>
+                    </TooltipTrigger>
+                    <TooltipContent>React</TooltipContent>
+                  </Tooltip>
+                  <PopoverContent
+                    align="end"
+                    className="w-auto p-0 rounded-2xl overflow-hidden border-0 bg-transparent shadow-none"
+                    side="top"
+                    sideOffset={10}
+                  >
+                    {reactionErrorMessage ? (
+                      <div className="px-3 pt-3 pb-0">
+                        <p className="text-xs text-destructive">
+                          {reactionErrorMessage}
+                        </p>
+                      </div>
+                    ) : null}
+                    <Picker
+                      data={data}
+                      onEmojiSelect={(emoji: { native: string }) => {
+                        void handleReactionSelect(emoji.native).finally(() => {
+                          setIsReactionPickerOpen(false);
+                        });
+                      }}
+                      theme="auto"
+                      previewPosition="none"
+                      skinTonePosition="search"
+                      set="native"
+                      maxFrequentRows={2}
+                      perLine={8}
+                    />
+                  </PopoverContent>
+                </Popover>
+              </div>
             </div>
-          </div>
-          <MessageTimestamp createdAt={message.createdAt} time={message.time} />
+          ) : null}
         </div>
       </div>
     </div>
diff --git a/desktop/src/features/messages/ui/TypingIndicatorRow.tsx b/desktop/src/features/messages/ui/TypingIndicatorRow.tsx
index 2a843ad9fc..cb0278c7c7 100644
--- a/desktop/src/features/messages/ui/TypingIndicatorRow.tsx
+++ b/desktop/src/features/messages/ui/TypingIndicatorRow.tsx
@@ -91,7 +91,6 @@ export function TypingIndicatorRow({
           className={cn(
             "flex w-full items-center gap-2",
             isActivityVariant && "h-full",
-            !isActivityVariant && "mx-auto max-w-4xl",
           )}
         >
           <div className="flex shrink-0 items-center">
diff --git a/desktop/src/shared/ui/ViewLoadingFallback.tsx b/desktop/src/shared/ui/ViewLoadingFallback.tsx
index 491b5f8455..64dbc4f2c8 100644
--- a/desktop/src/shared/ui/ViewLoadingFallback.tsx
+++ b/desktop/src/shared/ui/ViewLoadingFallback.tsx
@@ -177,13 +177,13 @@ function ChannelLoadingBody() {
   return (
     <div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
       <div className="flex-1 overflow-y-auto px-4 py-3 sm:px-6">
-        <div className="mx-auto flex w-full max-w-4xl flex-col gap-4">
+        <div className="flex w-full flex-col gap-4">
           <MessageRowsSkeleton />
         </div>
       </div>
 
       <div className="border-t border-border/60 bg-background px-4 py-4 sm:px-6">
-        <div className="mx-auto w-full max-w-4xl space-y-3">
+        <div className="w-full space-y-3">
           <Skeleton className="h-10 w-full rounded-2xl" />
           <div className="flex items-center gap-2">
             <Skeleton className="h-8 w-20 rounded-lg" />
diff --git a/web/src/features/repos/ui/RepoDetailPage.tsx b/web/src/features/repos/ui/RepoDetailPage.tsx
index 52bd17fcc2..8c86ffe4bc 100644
--- a/web/src/features/repos/ui/RepoDetailPage.tsx
+++ b/web/src/features/repos/ui/RepoDetailPage.tsx
@@ -60,7 +60,7 @@ function CopyableUrl({ url }: { url: string }) {
 
 function DetailSkeleton() {
   return (
-    <div className="mx-auto flex w-full max-w-7xl gap-8 px-4 py-8">
+    <div className="flex w-full gap-8 px-4 py-8">
       <div className="min-w-0 flex-1">
         <div className="h-5 w-24 animate-pulse rounded bg-muted" />
         <div className="mt-6 h-8 w-64 animate-pulse rounded bg-muted" />
@@ -181,7 +181,7 @@ export function RepoDetailPage() {
 
   if (!repo) {
     return (
-      <div className="mx-auto flex w-full max-w-7xl gap-8 px-4 py-8">
+      <div className="flex w-full gap-8 px-4 py-8">
         <div className="min-w-0 flex-1">
           <Link
             to="/"
@@ -205,7 +205,7 @@ export function RepoDetailPage() {
   }
 
   return (
-    <div className="mx-auto flex w-full max-w-7xl gap-8 px-4 py-8">
+    <div className="flex w-full gap-8 px-4 py-8">
       {/* Main content */}
       <div className="min-w-0 flex-1">
         {/* Back link */}
diff --git a/web/src/features/repos/ui/ReposPage.tsx b/web/src/features/repos/ui/ReposPage.tsx
index 0cdadc108d..0e1ecdb853 100644
--- a/web/src/features/repos/ui/ReposPage.tsx
+++ b/web/src/features/repos/ui/ReposPage.tsx
@@ -101,7 +101,7 @@ export function ReposPage() {
 
   if (isLoading) {
     return (
-      <div className="mx-auto flex w-full max-w-7xl gap-8 px-4 py-8">
+      <div className="flex w-full gap-8 px-4 py-8">
         <div className="min-w-0 flex-1">
           <h2 className="mb-4 flex items-center gap-2 text-lg font-semibold">
             <BookMarked className="h-5 w-5" /> Repositories
@@ -122,7 +122,7 @@ export function ReposPage() {
   }
 
   return (
-    <div className="mx-auto flex w-full max-w-7xl gap-8 px-4 py-8">
+    <div className="flex w-full gap-8 px-4 py-8">
       {/* Main content */}
       <div className="min-w-0 flex-1">
         {/* Mobile-only connect button */}

From ff3ee67d2f3997b13f3c0bdc6b910512d2854a2e Mon Sep 17 00:00:00 2001
From: Thomas Petersen <thomasp@squareup.com>
Date: Thu, 14 May 2026 21:05:55 -0400
Subject: [PATCH 2/5] fix(ui): align home timestamps and loading skeletons

Co-authored-by: Cursor <cursoragent@cursor.com>
---
 .../src/features/home/ui/InboxDetailPane.tsx  | 78 +++++++++----------
 .../features/messages/ui/TimelineSkeleton.tsx | 13 ++--
 desktop/src/shared/ui/ViewLoadingFallback.tsx | 15 ++--
 3 files changed, 55 insertions(+), 51 deletions(-)

diff --git a/desktop/src/features/home/ui/InboxDetailPane.tsx b/desktop/src/features/home/ui/InboxDetailPane.tsx
index ca76f71165..151a1f5415 100644
--- a/desktop/src/features/home/ui/InboxDetailPane.tsx
+++ b/desktop/src/features/home/ui/InboxDetailPane.tsx
@@ -277,7 +277,7 @@ export function InboxDetailPane({
                 <div className="px-6 py-2">
                   <article
                     className={cn(
-                      "group/message flex items-start gap-2.5 px-2 py-1 transition-colors duration-1000",
+                      "group/message relative flex items-start gap-2.5 px-2 py-1 transition-colors duration-1000",
                       message.isSelected
                         ? cn(
                             isFocusHighlightVisible
@@ -292,6 +292,39 @@ export function InboxDetailPane({
                         : "home-inbox-context-message"
                     }
                   >
+                    {canReply || onToggleReaction ? (
+                      <div className="absolute right-2 top-1 z-10">
+                        <MessageActionBar
+                          activeReplyTargetId={replyTargetId}
+                          message={toActionBarMessage(message)}
+                          onReactionSelect={
+                            onToggleReaction
+                              ? (emoji) => {
+                                  const actionBarMessage =
+                                    toActionBarMessage(message);
+                                  const remove =
+                                    actionBarMessage.reactions?.some(
+                                      (reaction) =>
+                                        reaction.emoji === emoji &&
+                                        reaction.reactedByCurrentUser,
+                                    ) ?? false;
+                                  return onToggleReaction(
+                                    actionBarMessage,
+                                    emoji,
+                                    remove,
+                                  );
+                                }
+                              : undefined
+                          }
+                          onReply={
+                            canReply
+                              ? () => handleSelectReplyTarget(message)
+                              : undefined
+                          }
+                          reactions={message.reactions ?? []}
+                        />
+                      </div>
+                    ) : null}
                     <UserAvatar
                       avatarUrl={message.avatarUrl}
                       className="h-8 w-8 shrink-0 rounded-xl"
@@ -299,53 +332,18 @@ export function InboxDetailPane({
                       size="md"
                     />
                     <div className="-mt-1 min-w-0 flex-1">
-                      <div className="flex min-w-0 flex-wrap items-start gap-x-2 gap-y-0">
+                      <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0">
                         <p className="truncate text-sm font-semibold leading-none tracking-tight text-foreground">
                           {message.authorLabel}
                         </p>
+                        <p className="shrink-0 text-xs font-normal leading-none tabular-nums text-muted-foreground/55">
+                          {message.fullTimestampLabel}
+                        </p>
                         {message.isSelected ? (
                           <span className="text-[10px] font-semibold uppercase leading-none tracking-[0.14em] text-muted-foreground/70">
                             Inbox item
                           </span>
                         ) : null}
-                        <p className="ml-auto text-xs text-muted-foreground">
-                          {message.fullTimestampLabel}
-                        </p>
-                        {canReply || onToggleReaction ? (
-                          <div className="relative ml-1">
-                            <div className="absolute right-0 top-1/2 -translate-y-1/2">
-                              <MessageActionBar
-                                activeReplyTargetId={replyTargetId}
-                                message={toActionBarMessage(message)}
-                                onReactionSelect={
-                                  onToggleReaction
-                                    ? (emoji) => {
-                                        const actionBarMessage =
-                                          toActionBarMessage(message);
-                                        const remove =
-                                          actionBarMessage.reactions?.some(
-                                            (reaction) =>
-                                              reaction.emoji === emoji &&
-                                              reaction.reactedByCurrentUser,
-                                          ) ?? false;
-                                        return onToggleReaction(
-                                          actionBarMessage,
-                                          emoji,
-                                          remove,
-                                        );
-                                      }
-                                    : undefined
-                                }
-                                onReply={
-                                  canReply
-                                    ? () => handleSelectReplyTarget(message)
-                                    : undefined
-                                }
-                                reactions={message.reactions ?? []}
-                              />
-                            </div>
-                          </div>
-                        ) : null}
                       </div>
                       <div className="mt-1">
                         <Markdown
diff --git a/desktop/src/features/messages/ui/TimelineSkeleton.tsx b/desktop/src/features/messages/ui/TimelineSkeleton.tsx
index f1132a2f60..d4d156a194 100644
--- a/desktop/src/features/messages/ui/TimelineSkeleton.tsx
+++ b/desktop/src/features/messages/ui/TimelineSkeleton.tsx
@@ -5,13 +5,16 @@ export function TimelineSkeleton() {
 
   return (
     <>
-      {skeletonRows.map((row) => (
+      {skeletonRows.map((row, index) => (
         <div className="flex gap-2.5" key={row}>
-          <Skeleton className="h-8 w-8 rounded-lg" />
+          <Skeleton className="h-9 w-9 shrink-0 rounded-xl" />
           <div className="min-w-0 flex-1 space-y-1">
-            <Skeleton className="h-3.5 w-44" />
-            <Skeleton className="h-4 w-full max-w-2xl" />
-            <Skeleton className="h-4 w-full max-w-xl" />
+            <div className="flex items-baseline gap-2">
+              <Skeleton className="h-3.5 w-28" />
+              <Skeleton className="h-3 w-12" />
+            </div>
+            <Skeleton className="h-4 w-full" />
+            <Skeleton className={index % 2 === 0 ? "h-4 w-4/5" : "h-4 w-2/3"} />
           </div>
         </div>
       ))}
diff --git a/desktop/src/shared/ui/ViewLoadingFallback.tsx b/desktop/src/shared/ui/ViewLoadingFallback.tsx
index 64dbc4f2c8..29243f7a9d 100644
--- a/desktop/src/shared/ui/ViewLoadingFallback.tsx
+++ b/desktop/src/shared/ui/ViewLoadingFallback.tsx
@@ -45,13 +45,16 @@ function LoadingHeaderSkeleton() {
 function MessageRowsSkeleton() {
   return (
     <>
-      {["first", "second", "third", "fourth", "fifth"].map((row) => (
+      {["first", "second", "third", "fourth", "fifth"].map((row, index) => (
         <div className="flex gap-3" key={row}>
-          <Skeleton className="h-8 w-8 shrink-0 rounded-lg" />
-          <div className="min-w-0 flex-1 space-y-2 pt-0.5">
-            <Skeleton className="h-3.5 w-40 max-w-[40%]" />
-            <Skeleton className="h-4 w-full max-w-3xl" />
-            <Skeleton className="h-4 w-full max-w-xl" />
+          <Skeleton className="h-9 w-9 shrink-0 rounded-xl" />
+          <div className="min-w-0 flex-1 space-y-1 pt-0.5">
+            <div className="flex items-baseline gap-2">
+              <Skeleton className="h-3.5 w-28" />
+              <Skeleton className="h-3 w-12" />
+            </div>
+            <Skeleton className="h-4 w-full" />
+            <Skeleton className={index % 2 === 0 ? "h-4 w-4/5" : "h-4 w-2/3"} />
           </div>
         </div>
       ))}

From cc368c6b88a2fc60697c7ba1be485fa77e306cac Mon Sep 17 00:00:00 2001
From: Thomas Petersen <thomasp@squareup.com>
Date: Thu, 14 May 2026 21:34:10 -0400
Subject: [PATCH 3/5] fix(desktop): keep profile button first in message rows

Co-authored-by: Cursor <cursoragent@cursor.com>
---
 desktop/src/features/messages/ui/MessageRow.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx
index b2728ebf8f..7455f1173a 100644
--- a/desktop/src/features/messages/ui/MessageRow.tsx
+++ b/desktop/src/features/messages/ui/MessageRow.tsx
@@ -289,7 +289,6 @@ export const MessageRow = React.memo(
           data-message-id={message.id}
           data-testid="message-row"
         >
-          {actionBarNode}
           {isThreadReplyLayout ? (
             <div className="flex min-w-0 items-start gap-1.5">
               {message.pubkey ? (
@@ -391,6 +390,7 @@ export const MessageRow = React.memo(
               </div>
             </>
           )}
+          {actionBarNode}
         </article>
       </div>
     );

From c7079ef8d87e1eb74d00ee3247b2a5ddf16e4cb7 Mon Sep 17 00:00:00 2001
From: Thomas Petersen <thomasp@squareup.com>
Date: Thu, 14 May 2026 21:53:30 -0400
Subject: [PATCH 4/5] fix(desktop): preserve compact thread reply layout

Co-authored-by: Cursor <cursoragent@cursor.com>
---
 .../src/features/messages/ui/MessageRow.tsx   | 63 ++++++++-----------
 1 file changed, 25 insertions(+), 38 deletions(-)

diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx
index 7455f1173a..ff80e85897 100644
--- a/desktop/src/features/messages/ui/MessageRow.tsx
+++ b/desktop/src/features/messages/ui/MessageRow.tsx
@@ -290,44 +290,31 @@ export const MessageRow = React.memo(
           data-testid="message-row"
         >
           {isThreadReplyLayout ? (
-            <div className="flex min-w-0 items-start gap-1.5">
-              {message.pubkey ? (
-                <UserProfilePopover
-                  pubkey={message.pubkey}
-                  role={message.role}
-                  botIdenticonValue={message.author}
-                >
-                  <button
-                    className={cn(
-                      "flex shrink-0 items-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
-                      avatarButtonRadiusClass,
-                    )}
-                    type="button"
+            <>
+              <div className="flex min-w-0 items-baseline gap-1.5">
+                {message.pubkey ? (
+                  <UserProfilePopover
+                    pubkey={message.pubkey}
+                    role={message.role}
+                    botIdenticonValue={message.author}
                   >
-                    {avatarNode}
-                  </button>
-                </UserProfilePopover>
-              ) : (
-                <div className="flex shrink-0 items-start">{avatarNode}</div>
-              )}
-              <div className="min-w-0 flex-1 space-y-0.5">
-                <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
-                  {message.pubkey ? (
-                    <UserProfilePopover
-                      pubkey={message.pubkey}
-                      role={message.role}
-                      botIdenticonValue={message.author}
+                    <button
+                      className="flex shrink-0 items-start gap-1.5 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
+                      type="button"
                     >
-                      <button
-                        className="truncate rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
-                        type="button"
-                      >
-                        {authorNode}
-                      </button>
-                    </UserProfilePopover>
-                  ) : (
-                    authorNode
-                  )}
+                      {avatarNode}
+                      {authorNode}
+                    </button>
+                  </UserProfilePopover>
+                ) : (
+                  <>
+                    <div className="flex shrink-0 items-start">
+                      {avatarNode}
+                    </div>
+                    {authorNode}
+                  </>
+                )}
+                <div className="flex min-w-0 flex-1 flex-wrap items-baseline gap-x-2 gap-y-0.5">
                   {inlineMetadataNode}
                   {message.personaDisplayName &&
                   message.personaDisplayName !== message.author ? (
@@ -336,9 +323,9 @@ export const MessageRow = React.memo(
                     </span>
                   ) : null}
                 </div>
-                <div className="min-w-0 space-y-0.5">{messageBodyNode}</div>
               </div>
-            </div>
+              <div className="min-w-0 space-y-0.5">{messageBodyNode}</div>
+            </>
           ) : (
             <>
               {message.pubkey ? (

From 6b41c023dabd6a43792067b85a96bb99a02f4027 Mon Sep 17 00:00:00 2001
From: thomaspblock <thomasp@squareup.com>
Date: Fri, 15 May 2026 17:10:28 -0400
Subject: [PATCH 5/5] chore(desktop): use thread-reply radius class

---
 desktop/src/features/messages/ui/MessageRow.tsx | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx
index ff80e85897..f201f77376 100644
--- a/desktop/src/features/messages/ui/MessageRow.tsx
+++ b/desktop/src/features/messages/ui/MessageRow.tsx
@@ -299,7 +299,10 @@ export const MessageRow = React.memo(
                     botIdenticonValue={message.author}
                   >
                     <button
-                      className="flex shrink-0 items-start gap-1.5 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
+                      className={cn(
+                        "flex shrink-0 items-start gap-1.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
+                        avatarButtonRadiusClass,
+                      )}
                       type="button"
                     >
                       {avatarNode}
