diff --git a/qa/flows/accounts.flow.ts b/qa/flows/accounts.flow.ts
new file mode 100644
index 000000000..62c05731a
--- /dev/null
+++ b/qa/flows/accounts.flow.ts
@@ -0,0 +1,27 @@
+import { expect, test } from "../lib/proof.ts";
+
+test("the accounts list reads on a phone as well as on a desktop", async ({ page, proof }) => {
+ await page.goto("/app/emails");
+ const row = page.getByRole("row", { name: /dev\.outbound@warmbly\.test/ });
+ await expect(row).toBeVisible();
+ await proof.chapter("Accounts", "The same list on a desktop, then on a phone");
+ await proof.shot("accounts-desktop", { caption: "Desktop: every metric has its own column" });
+
+ // The list's columns follow its own width, so the phone layout is a viewport change away.
+ await page.setViewportSize({ width: 390, height: 844 });
+ await expect(row.getByText("dev.outbound@warmbly.test")).toBeVisible();
+ await expect(row.getByText("Health", { exact: true })).toBeVisible();
+ await proof.dwell();
+ await proof.shot("accounts-phone", { caption: "Phone: address, sender and connection, then labelled warmup, inbox and health readings" });
+
+ await page.getByRole("textbox", { name: /Search by email/ }).pressSequentially("outbound", { delay: 60 });
+ await expect(page.getByRole("row", { name: /dev\.send@warmbly\.test/ })).toBeHidden();
+ await expect(row).toBeVisible();
+ await proof.shot("accounts-phone-search", { caption: "Search and the tag filter share one row" });
+
+ // From the keyboard: on a phone-sized page the dev-only query devtools sit over the last row's actions.
+ await row.getByRole("button", { name: "Mailbox actions" }).focus();
+ await page.keyboard.press("Enter");
+ await expect(page.getByRole("menuitem", { name: /Disconnect mailbox/ })).toBeVisible();
+ await proof.shot("accounts-phone-actions", { caption: "Row actions stay reachable at touch size" });
+});
diff --git a/web/src/app/app/emails/page.tsx b/web/src/app/app/emails/page.tsx
index 93262e8d6..28840be89 100644
--- a/web/src/app/app/emails/page.tsx
+++ b/web/src/app/app/emails/page.tsx
@@ -401,7 +401,7 @@ export default function AddressesPage() {
>
}>
- Sending domains
+ Sending domains p?.setAddEmail(true)}
@@ -423,7 +423,7 @@ export default function AddressesPage() {
value={query}
onChange={setQuery}
placeholder="Search by email…"
- className="w-full sm:w-56"
+ className="flex-1 sm:flex-none sm:w-56"
/>
@@ -511,58 +511,61 @@ export default function AddressesPage() {
) : (
// table-fixed like the Leads list: every column but Mailbox
// carries a width, so one long address never widens the table.
-
-
-
-
- {
- if (isSelectedAll()) {
- setSelected((bef) =>
- bef.filter((e) => !emailsData.emails.map((em) => em.id).includes(e)),
- );
- } else {
- setSelected((bef) => [
- ...bef,
- ...emailsData.emails
- .filter((em) => !selected.includes(em.id))
- .map((em) => em.id),
- ]);
- }
- }}
+ // Columns key off the list's own width, not the viewport, since the sidebar takes a share of it.
+