diff --git a/app/__tests__/focus-visible.test.js b/app/__tests__/focus-visible.test.js index 42217915..fa659c3d 100644 --- a/app/__tests__/focus-visible.test.js +++ b/app/__tests__/focus-visible.test.js @@ -18,6 +18,11 @@ describe("focus-visible CSS layer", () => { expect(css).toContain("outline-offset:"); }); + it("focus.css targets rows marked as actively focused", () => { + const css = fs.readFileSync(focusCssPath, "utf8"); + expect(css).toContain('[data-focus-visible="true"]'); + }); + it("focus.css provides a dark-mode adjustment rule", () => { const css = fs.readFileSync(focusCssPath, "utf8"); expect(css).toContain(".dark :focus-visible"); diff --git a/app/styles/focus.css b/app/styles/focus.css index 46b14243..1a579d54 100644 --- a/app/styles/focus.css +++ b/app/styles/focus.css @@ -29,7 +29,7 @@ * offset so it remains visible on both light and dark backgrounds. */ :focus-visible, - [data-focus-visible] { + [data-focus-visible="true"] { outline: 3px solid hsl(var(--ring, 210 100% 56%)); outline-offset: 2px; border-radius: var(--radius, 0.375rem); @@ -44,7 +44,7 @@ * white inner shadow acts as a separator without adding DOM nodes. */ .dark :focus-visible, - .dark [data-focus-visible] { + .dark [data-focus-visible="true"] { box-shadow: 0 0 0 2px hsl(var(--background, 222 47% 11%)); } diff --git a/app/styles/touch.css b/app/styles/touch.css index b5e541d3..a8d9ca3e 100644 --- a/app/styles/touch.css +++ b/app/styles/touch.css @@ -41,4 +41,24 @@ min-height: 44px; min-width: 44px; } + + .touch-ripple { + position: relative; + overflow: hidden; + } + + .touch-ripple:active::after { + content: ""; + position: absolute; + inset: 0; + background: rgba(148, 163, 184, 0.18); + border-radius: inherit; + pointer-events: none; + animation: touch-ripple 220ms ease-out; + } + + @keyframes touch-ripple { + from { opacity: 1; transform: scale(0.96); } + to { opacity: 0; transform: scale(1); } + } } diff --git a/components/PredictionCard.tsx b/components/PredictionCard.tsx index 3c18b593..8b4ff332 100644 --- a/components/PredictionCard.tsx +++ b/components/PredictionCard.tsx @@ -105,7 +105,7 @@ const PredictionCard: React.FC = ({ prediction }) => { return ( /* touch-target: enforces ≥44px hit area (WCAG 2.5.5 / Apple HIG). */ -