diff --git a/ui/e2e/social.spec.ts b/ui/e2e/social.spec.ts
index 331df8b..33cdd70 100644
--- a/ui/e2e/social.spec.ts
+++ b/ui/e2e/social.spec.ts
@@ -165,12 +165,14 @@ test('link account: the Telegram web sign-in control is offered in a browser', a
await expect(page.getByRole('button', { name: 'Link Telegram' })).toBeVisible();
});
-test('chat send and nudge are icon buttons', async ({ page }) => {
+test('chat: the message field shows on your turn, the nudge replaces it otherwise', async ({ page }) => {
await loginLobby(page);
- await page.getByRole('button', { name: /Ann/ }).click();
+ await page.getByRole('button', { name: /Ann/ }).click(); // g1: your turn
await page.locator('.burger').first().click();
await page.getByRole('button', { name: 'Chat' }).click();
- // Icon-only controls expose their action through the aria-label.
+ // On your turn the message field + Send are shown and the nudge is hidden (Stage 17);
+ // chat and nudge are mutually exclusive by turn. Icon-only controls expose their action
+ // through the aria-label.
await expect(page.getByRole('button', { name: 'Send' })).toBeVisible();
- await expect(page.getByRole('button', { name: 'Nudge' })).toBeVisible();
+ await expect(page.getByRole('button', { name: 'Nudge' })).toHaveCount(0);
});
diff --git a/ui/src/game/Board.svelte b/ui/src/game/Board.svelte
index 7f6637b..a434519 100644
--- a/ui/src/game/Board.svelte
+++ b/ui/src/game/Board.svelte
@@ -250,6 +250,9 @@
border-radius: 1px;
background: var(--cell-bg);
color: var(--prem-text);
+ /* No mobile tap flash on a cell tap (parity with the web click; the only intentional
+ cell animation is the last-word .flash highlight). */
+ -webkit-tap-highlight-color: transparent;
padding: 0;
overflow: hidden;
font-size: 0;
diff --git a/ui/src/game/Chat.svelte b/ui/src/game/Chat.svelte
index 7d12318..fb1ddb9 100644
--- a/ui/src/game/Chat.svelte
+++ b/ui/src/game/Chat.svelte
@@ -6,16 +6,20 @@
messages,
myId,
busy,
- canNudge = true,
+ myTurn = false,
+ nudgeOnCooldown = false,
onsend,
onnudge,
}: {
messages: ChatMessage[];
myId: string;
busy: boolean;
- // Nudging only makes sense while waiting on the opponent; it is disabled on the
- // player's own turn (there is no one to hurry along).
- canNudge?: boolean;
+ // Chat and nudge are mutually exclusive by turn (Stage 17): on the player's own turn the
+ // message field + send are shown (and nudging makes no sense — there is no one to
+ // hurry); on the opponent's turn only the nudge button shows. While the hourly nudge
+ // cooldown is active the nudge is disabled with an "awaiting reply" caption.
+ myTurn?: boolean;
+ nudgeOnCooldown?: boolean;
onsend: (text: string) => void;
onnudge: () => void;
} = $props();
@@ -44,14 +48,18 @@
{/each}