Button

rest
hover · darken
focus-visible
disabled · 45%

Input

rest
focus-visible
aria-invalid
disabled

Status — a dot and a word, never a background wash

Not started
In progress
Complete
Expiring
Failed

Loading & empty

skeleton · >1s waits

No courses yet

What is missing, why, and one thing to do — all three are required.

Focus is never removed, only restyled — :focus-visible so a mouse click does not paint a ring the user did not ask for. Invalid state is driven by aria-invalid rather than a CSS class, so what is seen and what is announced cannot drift apart. Press is an instant opacity dim: no bounce, no lift.