From 738811dbe7d1b887005820826fbb6b91c1eb439a Mon Sep 17 00:00:00 2001
From: cynarAI <155274210+cynarAI@users.noreply.github.com>
Date: Mon, 5 Oct 2026 12:42:30 +0200
Subject: [PATCH] Read the web app at 16px base size on phones (#155)
Text sizes now follow a --font-scale variable that is 1 on wider screens and
8/7 below 768px, so the 14px base text reads at 16px on phones (Safari stops
zooming into fields at that size) and every other size grows by the same
ratio. One-off pixel sizes in the shell move onto the shared text tokens so
they scale too. The stage subtitle now truncates inside the screen instead
of spilling past both edges.
Claude-Session: https://claude.ai/code/session_01PFEDgbyJm12ExL3Kn4Dk8B
Co-authored-by: Claude
---
apps/web/e2e/mobile-font-size.spec.ts | 41 +++++++++++++++++++
apps/web/src/components/stage/OoStage.tsx | 4 +-
.../pages/ExternalConversationSettings.tsx | 5 ++-
apps/web/src/pages/PeerMessagesOverlay.tsx | 2 +-
apps/web/src/pages/PluginsOverlay.tsx | 4 +-
apps/web/src/pages/RoutineEditor.tsx | 6 +--
apps/web/src/pages/RoutineSchedule.tsx | 4 +-
apps/web/src/pages/ScratchpadSection.tsx | 2 +-
apps/web/src/pages/Welcome.tsx | 2 +-
apps/web/src/pages/shell/message-cards.tsx | 4 +-
apps/web/src/pages/shell/transcript.tsx | 12 +++---
apps/web/src/pages/shell/user-menu.tsx | 2 +-
apps/web/src/styles.css | 6 +--
packages/ui-web/src/styles.css | 34 +++++++++++----
14 files changed, 96 insertions(+), 32 deletions(-)
create mode 100644 apps/web/e2e/mobile-font-size.spec.ts
diff --git a/apps/web/e2e/mobile-font-size.spec.ts b/apps/web/e2e/mobile-font-size.spec.ts
new file mode 100644
index 0000000..759b6af
--- /dev/null
+++ b/apps/web/e2e/mobile-font-size.spec.ts
@@ -0,0 +1,41 @@
+import { expect, type Locator, test } from "@playwright/test";
+import { captureScreenshot, completeOnboarding, signup } from "./helpers";
+
+async function fontSize(locator: Locator) {
+ return locator.evaluate((element) => Number.parseFloat(getComputedStyle(element).fontSize));
+}
+
+test("phone widths read text at 16px and up while desktop keeps its sizes", async ({
+ page,
+}, testInfo) => {
+ const stamp = Date.now();
+ await signup(page, `mobile-font-${stamp}@rakazo.test`, "password12", "Font QA");
+ await completeOnboarding(page);
+
+ const composer = page.getByRole("combobox", { name: /^Message/ });
+ await composer.fill("Please review `shared/PROJECT_CHECKPOINT_WRAPUP.md`.");
+ await composer.press("Enter");
+ const reply = page
+ .getByTestId("transcript")
+ .locator("[data-message-id]")
+ .filter({ hasText: "done. i handled:" });
+ await expect(reply).toBeVisible({ timeout: 30_000 });
+
+ const smallText = page.locator(".text-ui-body-sm").first();
+ const desktopSmall = await fontSize(smallText);
+ expect(desktopSmall).toBe(14);
+
+ await page.setViewportSize({ width: 390, height: 844 });
+ await expect.poll(() => fontSize(smallText)).toBeCloseTo(16, 1);
+ expect(await fontSize(composer)).toBeGreaterThanOrEqual(16);
+
+ await page.emulateMedia({ colorScheme: "dark" });
+ await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
+ await captureScreenshot(page, testInfo, "mobile-font-size-dark");
+ await page.emulateMedia({ colorScheme: "light" });
+ await expect(page.locator("html")).toHaveAttribute("data-theme", "light");
+ await captureScreenshot(page, testInfo, "mobile-font-size-light");
+
+ await page.setViewportSize({ width: 1280, height: 720 });
+ await expect.poll(() => fontSize(smallText)).toBe(desktopSmall);
+});
diff --git a/apps/web/src/components/stage/OoStage.tsx b/apps/web/src/components/stage/OoStage.tsx
index e30c59d..c6b5d23 100644
--- a/apps/web/src/components/stage/OoStage.tsx
+++ b/apps/web/src/components/stage/OoStage.tsx
@@ -251,7 +251,7 @@ export function OoStage({
) : null}
>
) : (
-
+
{subtitle}
)}
@@ -548,7 +548,7 @@ export function OoGroupStage({
{subtitle}
) : (
-
+
{subtitle}
)}
diff --git a/apps/web/src/pages/ExternalConversationSettings.tsx b/apps/web/src/pages/ExternalConversationSettings.tsx
index 0b00102..396bb96 100644
--- a/apps/web/src/pages/ExternalConversationSettings.tsx
+++ b/apps/web/src/pages/ExternalConversationSettings.tsx
@@ -80,7 +80,10 @@ export function ExternalConversationSettings({
return (
-
+
{conversation.displayName || t`External conversation`}
diff --git a/apps/web/src/pages/PeerMessagesOverlay.tsx b/apps/web/src/pages/PeerMessagesOverlay.tsx
index 5c61241..b8c8451 100644
--- a/apps/web/src/pages/PeerMessagesOverlay.tsx
+++ b/apps/web/src/pages/PeerMessagesOverlay.tsx
@@ -134,7 +134,7 @@ export function PeerMessagesOverlay({
{sent ? botName : peerBotName}
-
diff --git a/apps/web/src/pages/PluginsOverlay.tsx b/apps/web/src/pages/PluginsOverlay.tsx
index 0c56fdc..01daf66 100644
--- a/apps/web/src/pages/PluginsOverlay.tsx
+++ b/apps/web/src/pages/PluginsOverlay.tsx
@@ -558,7 +558,9 @@ export function PluginsOverlay({
{item.name[0]}
)}
-
{item.name}
+
+ {item.name}
+