diff --git a/src/client/styles.css b/src/client/styles.css index 974bcf2..6821d7a 100644 --- a/src/client/styles.css +++ b/src/client/styles.css @@ -306,7 +306,9 @@ body { font-family: var(--mono); font-size: 12px; padding: 5px 13px; - transition: all 0.16s ease; + transition: + color 0.16s ease, + border-color 0.16s ease; } .chip:hover { @@ -481,7 +483,9 @@ body { letter-spacing: 0.03em; padding: 11px; border-radius: 8px; - transition: all 0.16s ease; + transition: + color 0.16s ease, + border-color 0.16s ease; } .btn-ghost:hover { @@ -534,13 +538,26 @@ body { } @media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - animation: none !important; - transition: none !important; - opacity: 1 !important; - transform: none !important; + [data-anim], + .scan__beam, + .scan__dot, + .ticker__caret { + animation: none; + } + + [data-anim] { + opacity: 1; + } + + .scan__dot { + transform: none; + } + + .btn-primary, + .chip, + .btn-ghost, + .btn-quiet { + transition: none; } } diff --git a/tests/e2e/card.spec.ts b/tests/e2e/card.spec.ts index f0bc631..8ed831e 100644 --- a/tests/e2e/card.spec.ts +++ b/tests/e2e/card.spec.ts @@ -153,3 +153,29 @@ test('a spent budget is stated plainly rather than spinning', async ({ page }) = await expect(page.getByRole('alert')).toContainText('generation budget'); }); + +test('reduced motion keeps the landing and loading screens static and readable', async ({ + page, +}) => { + await page.emulateMedia({ reducedMotion: 'reduce' }); + await stubApi(page, {}); + await page.goto('/'); + + for (const element of await page.locator('[data-anim]').all()) { + await expect(element).toHaveCSS('animation-name', 'none'); + await expect(element).toHaveCSS('opacity', '1'); + } + for (const element of await page.locator('.btn-primary, .chip, .footer__social').all()) { + await expect(element).toHaveCSS('transition-duration', '0s'); + } + + await page.getByLabel('GitHub repository, as owner/repo').fill('atlas/pipeline'); + await page.getByRole('button', { name: 'Read →' }).click(); + await expect(page.getByRole('heading', { level: 2 })).toContainText('Cortex is reading'); + await expect(page.locator('.scan__beam')).toBeVisible(); + for (const element of await page.locator('.scan__beam, .scan__dot, .ticker__caret').all()) { + await expect(element).toHaveCSS('animation-name', 'none'); + await expect(element).toHaveCSS('opacity', '1'); + } + await expect(page.locator('.scan__dot').first()).toHaveCSS('transform', 'none'); +});