diff --git a/desktop/src/features/home/ui/InboxMessageRow.tsx b/desktop/src/features/home/ui/InboxMessageRow.tsx
index 686a00dd61..52667967cb 100644
--- a/desktop/src/features/home/ui/InboxMessageRow.tsx
+++ b/desktop/src/features/home/ui/InboxMessageRow.tsx
@@ -209,7 +209,7 @@ export function InboxMessageRow({
{isContinuation ? null : (
+
{timestampNode}
diff --git a/desktop/src/features/messages/ui/MessageAgentOwner.tsx b/desktop/src/features/messages/ui/MessageAgentOwner.tsx
index e394d567b4..717c8aa4c7 100644
--- a/desktop/src/features/messages/ui/MessageAgentOwner.tsx
+++ b/desktop/src/features/messages/ui/MessageAgentOwner.tsx
@@ -11,30 +11,13 @@ export function MessageAgentOwner({
}) {
return (
{ownerLabel ? "Agent managed by" : "Agent; owner unavailable"}
- {/*
- * Icon and label sit directly in this baseline row rather than in a nested
- * flex wrapper, so the label's own baseline is what aligns with the author
- * name beside it. Both branches share the icon for the same reason: two
- * wrappers meant two alignment rules and the "owner unavailable" variant
- * had drifted a pixel off the other one.
- *
- * `self-center` keeps the icon out of baseline alignment, so the label —
- * not the icon's box — sets this chip's baseline. Centred on the line box
- * the glyph's ink still rides ~1.6px above the text's cap band, reading as
- * a couple of pixels too high; 0.125em drops its optical centre onto that
- * band. In em so it holds under Cmd +/- zoom, and as a transform so it
- * shifts nothing else in the row.
- */}
-
+
{ownerPubkey && ownerLabel ? (
<>
diff --git a/desktop/tests/e2e/messaging.spec.ts b/desktop/tests/e2e/messaging.spec.ts
index 67641d1c38..a4ec67b175 100644
--- a/desktop/tests/e2e/messaging.spec.ts
+++ b/desktop/tests/e2e/messaging.spec.ts
@@ -49,6 +49,18 @@ async function expectThreadReplyUnobscured(row: Locator) {
.toBe(true);
}
+async function measureInlineBaseline(locator: Locator) {
+ return locator.evaluate((element) => {
+ const marker = document.createElement("span");
+ marker.style.cssText =
+ "display:inline-block;width:0;height:0;margin:0;padding:0;border:0";
+ element.append(marker);
+ const baseline = marker.getBoundingClientRect().top;
+ marker.remove();
+ return baseline;
+ });
+}
+
async function measureThreadSummaryGeometry(summaryRow: Locator) {
return summaryRow.evaluate((summaryButton) => {
const summaryWrapper = summaryButton.parentElement;
@@ -396,6 +408,64 @@ test("agent owner label identifies the agent and owner", async ({ page }) => {
await expect(ownerTreatment.locator(".sr-only")).toHaveText(
"Agent managed by",
);
+
+ const author = aliceMessage.getByTestId("message-author");
+ const managedBy = ownerTreatment.getByText("managed by", { exact: true });
+ const owner = ownerTreatment.locator(".font-semibold");
+ const timestamp = aliceMessage.getByTestId("message-timestamp");
+
+ for (const fontSize of ["smaller", "default", "larger"]) {
+ await page.evaluate((value) => {
+ document.documentElement.dataset.fontSize = value;
+ }, fontSize);
+
+ const [
+ authorBaseline,
+ managedByBaseline,
+ ownerBaseline,
+ timestampBaseline,
+ ] = await Promise.all([
+ measureInlineBaseline(author),
+ measureInlineBaseline(managedBy),
+ measureInlineBaseline(owner),
+ measureInlineBaseline(timestamp),
+ ]);
+ const [ownerTypography, timestampTypography] = await Promise.all([
+ ownerTreatment.evaluate((element) => {
+ const style = getComputedStyle(element);
+ return { fontSize: style.fontSize, lineHeight: style.lineHeight };
+ }),
+ timestamp.evaluate((element) => {
+ const style = getComputedStyle(element);
+ return { fontSize: style.fontSize, lineHeight: style.lineHeight };
+ }),
+ ]);
+ const iconCenterOffset = await ownerTreatment.evaluate((element) => {
+ const icon = element.querySelector("svg");
+ if (!icon) throw new Error("Expected the agent owner icon.");
+ const ownerRect = element.getBoundingClientRect();
+ const iconRect = icon.getBoundingClientRect();
+ return (
+ iconRect.top +
+ iconRect.height / 2 -
+ (ownerRect.top + ownerRect.height / 2)
+ );
+ });
+
+ expect(
+ { managedByBaseline, ownerBaseline, timestampBaseline },
+ `message header baselines at ${fontSize} font size`,
+ ).toEqual({
+ managedByBaseline: authorBaseline,
+ ownerBaseline: authorBaseline,
+ timestampBaseline: authorBaseline,
+ });
+ expect(ownerTypography).toEqual(timestampTypography);
+ expect(
+ Math.abs(iconCenterOffset),
+ `agent icon center at ${fontSize} font size`,
+ ).toBeLessThan(0.01);
+ }
});
test("send a message and see it in timeline", async ({ page }) => {