fix(a11y): reduced-motion for spinner/call-avatar; tap-to-skip boot; AA accent contrast
- SendingSpinClass and CallAvatarAnimation respect prefers-reduced-motion (static opacity fallback), matching MsgAppearClass. - Terminal boot overlay dismisses on click/tap and is aria-hidden. - Primary.Main: Midnight #6b7ca8 -> #6f80aa (4.29 -> 4.51:1), Lotus Terminal Light #c44e00 -> #ba4a00 (4.14 -> 4.52:1), hue preserved. Fixes #84 Fixes #86 Fixes #52 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -36,25 +36,46 @@ const glowPulse = keyframes({
|
||||
},
|
||||
});
|
||||
|
||||
// Wobble/glow/spin only run under the same no-preference guard as
|
||||
// MsgAppearClass below; prefers-reduced-motion users get a static state.
|
||||
export const WobbleAnimation = style({
|
||||
'@media': {
|
||||
'(prefers-reduced-motion: no-preference)': {
|
||||
animation: `${wobble} 2000ms ease-in-out`,
|
||||
animationIterationCount: 'infinite',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const GlowAnimation = style({
|
||||
'@media': {
|
||||
'(prefers-reduced-motion: no-preference)': {
|
||||
animation: `${glowPulse} 2000ms ease-out`,
|
||||
animationIterationCount: 'infinite',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const CallAvatarAnimation = style({
|
||||
'@media': {
|
||||
'(prefers-reduced-motion: no-preference)': {
|
||||
animation: `${wobble} 2000ms ease-in-out, ${glowPulse} 2000ms ease-out`,
|
||||
animationIterationCount: 'infinite',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const SendingSpinClass = style({
|
||||
display: 'inline-block',
|
||||
animation: `${spin} 900ms linear infinite`,
|
||||
transformOrigin: 'center',
|
||||
// Static fallback: dim instead of spinning when motion is reduced.
|
||||
opacity: 0.6,
|
||||
'@media': {
|
||||
'(prefers-reduced-motion: no-preference)': {
|
||||
animation: `${spin} 900ms linear infinite`,
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const msgAppearKeyframe = keyframes({
|
||||
|
||||
+6
-2
@@ -500,7 +500,9 @@ export const midnightTheme = createTheme(color, {
|
||||
},
|
||||
|
||||
Primary: {
|
||||
Main: '#6b7ca8',
|
||||
// #6b7ca8 measured 4.29:1 against Background.Container (#111827), below
|
||||
// WCAG AA 4.5:1. Lightened along the same hue/saturation to 4.51:1.
|
||||
Main: '#6f80aa',
|
||||
MainHover: '#7989b1',
|
||||
MainActive: '#8493b8',
|
||||
MainLine: '#8f9dbf',
|
||||
@@ -651,7 +653,9 @@ export const lotusTerminalLightTheme = createTheme(color, {
|
||||
OnContainer: '#2d3d56',
|
||||
},
|
||||
Primary: {
|
||||
Main: '#c44e00',
|
||||
// #c44e00 measured 4.14:1 against Background.Container (#edf0f5), below
|
||||
// WCAG AA 4.5:1. Darkened along the same hue/saturation to 4.52:1.
|
||||
Main: '#ba4a00',
|
||||
MainHover: '#a33f00',
|
||||
MainActive: '#8f3700',
|
||||
MainLine: '#d45800',
|
||||
|
||||
@@ -34,6 +34,8 @@ export function runLotusBootSequence(force = false): void {
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'lt-boot';
|
||||
// Decorative boot animation, not content — hide it from assistive tech.
|
||||
overlay.setAttribute('aria-hidden', 'true');
|
||||
overlay.style.cssText = [
|
||||
'position:fixed',
|
||||
'inset:0',
|
||||
@@ -79,6 +81,7 @@ export function runLotusBootSequence(force = false): void {
|
||||
const dismiss = (): void => {
|
||||
clearInterval(interval);
|
||||
document.removeEventListener('keydown', onKey);
|
||||
overlay.removeEventListener('click', dismiss);
|
||||
overlay.style.transition = 'opacity 0.4s ease';
|
||||
overlay.style.opacity = '0';
|
||||
setTimeout(() => overlay.remove(), 400);
|
||||
@@ -88,6 +91,9 @@ export function runLotusBootSequence(force = false): void {
|
||||
if (e.key === 'Escape') dismiss();
|
||||
};
|
||||
document.addEventListener('keydown', onKey);
|
||||
// No touch/click dismiss previously existed — mouse/touch users had no way
|
||||
// to skip besides the keyboard-only Escape hint.
|
||||
overlay.addEventListener('click', dismiss);
|
||||
|
||||
let i = 0;
|
||||
let text = '';
|
||||
|
||||
Reference in New Issue
Block a user