diff --git a/src/app.css b/src/app.css index a5be2c2d78..93d3b0601e 100644 --- a/src/app.css +++ b/src/app.css @@ -865,77 +865,115 @@ body { padding-bottom: 2rem; /* space for the bottom toolbar */ } -/* High Contrast Mode: placeholders bottom out at 1.58:1 (WCAG 1.4.3 wants 4.5:1). */ +/* Accessibility Mode: placeholders bottom out at 1.58:1 (WCAG 1.4.3 wants 4.5:1). */ @layer utilities { html.high-contrast:not(.dark) :is(input, textarea)::placeholder { - color: var(--color-gray-600); + color: var(--color-gray-700); } html.high-contrast.dark :is(input, textarea)::placeholder { - color: var(--color-gray-500); + color: var(--color-gray-300); } } -/* High Contrast Mode: muted text fails WCAG 1.4.3 (2.07:1 light, 3.12:1 dark). +/* Accessibility Mode: muted text fails WCAG 1.4.3 (2.07:1 light, 3.12:1 dark). :where() keeps these at low specificity so hover variants still win. */ @layer utilities { html:where(.high-contrast):not(:where(.dark)) .text-gray-400 { - color: var(--color-gray-600); + color: var(--color-gray-700); } - html:where(.high-contrast).dark .dark\:text-gray-600 { - color: var(--color-gray-400); + html:where(.high-contrast).dark :is(.dark\:text-gray-400, .dark\:text-gray-500, .dark\:text-gray-600) { + color: var(--color-gray-300); + } + + html:where(.high-contrast).dark + :is( + .dark\:hover\:text-gray-100:hover, + .dark\:hover\:text-gray-200:hover, + .dark\:hover\:text-gray-300:hover, + .dark\:hover\:text-gray-400:hover + ) { + color: #fff; } /* Elements that hover to a lighter grey than the new resting colour. */ - html:where(.high-contrast):not(:where(.dark)) .hover\:text-gray-500:hover { - color: var(--color-gray-800); + html:where(.high-contrast):not(:where(.dark)) + :is( + .hover\:text-gray-500:hover, + .hover\:text-gray-600:hover, + .hover\:text-gray-700:hover, + .hover\:text-gray-800:hover + ) { + color: var(--color-gray-900); } } -/* High Contrast Mode: gray-500 muted text is 2.77:1 in light (WCAG 1.4.3 wants 4.5:1). +/* Accessibility Mode: gray-500 muted text is 2.77:1 in light (WCAG 1.4.3 wants 4.5:1). The utility stays in the layer so hover variants still outrank it; the classes below are unlayered, so their override has to be too. */ @layer utilities { - html:where(.high-contrast):not(:where(.dark)) .text-gray-500 { - color: var(--color-gray-600); + html:where(.high-contrast):not(:where(.dark)) :is(.text-gray-500, .text-gray-600) { + color: var(--color-gray-700); } } html.high-contrast:not(.dark) :is(.app-muted, .app-icon-muted, .tiptap table) { - color: var(--color-gray-600); + color: var(--color-gray-700); } -/* High Contrast Mode: the lightest muted pair, 1.58:1 in light and 2.14:1 in dark. +html.high-contrast.dark :is(.app-muted, .app-icon-muted, .tiptap table) { + color: var(--color-gray-300); +} + +/* Accessibility Mode: the lightest muted pair, 1.58:1 in light and 2.14:1 in dark. text-gray-400/70 is an icon colour, so 1.4.11 governs it, and 2.07:1 misses that too. */ @layer utilities { html:where(.high-contrast):not(:where(.dark)) :is(.text-gray-300, .text-gray-400\/70) { - color: var(--color-gray-600); + color: var(--color-gray-700); } - html:where(.high-contrast).dark .dark\:text-gray-700 { - color: var(--color-gray-400); + html:where(.high-contrast).dark :is(.dark\:text-gray-700, .dark\:text-gray-800) { + color: var(--color-gray-300); } /* Hover states that land lighter than the new resting colour. */ - html:where(.high-contrast):not(:where(.dark)) .hover\:text-gray-500:hover { - color: var(--color-gray-800); + html:where(.high-contrast):not(:where(.dark)) + :is( + .hover\:text-gray-500:hover, + .hover\:text-gray-600:hover, + .hover\:text-gray-700:hover, + .hover\:text-gray-800:hover + ) { + color: var(--color-gray-900); } - html:where(.high-contrast):not(:where(.dark)) .group:hover .group-hover\:text-gray-500 { - color: var(--color-gray-800); + html:where(.high-contrast):not(:where(.dark)) + .group:hover + :is(.group-hover\:text-gray-500, .group-hover\:text-gray-600, .group-hover\:text-gray-700) { + color: var(--color-gray-900); + } + + html:where(.high-contrast).dark + .group:hover + :is( + .dark\:group-hover\:text-gray-200, + .dark\:group-hover\:text-gray-300, + .dark\:group-hover\:text-gray-400 + ) { + color: #fff; } } /* Autocompletion ghost text is 2.65:1 in light; the dark canvas already passes. */ html.high-contrast:not(.dark) .ai-autocompletion::after { - color: var(--color-gray-600); + color: var(--color-gray-700); } /* The shimmer gradient is 2.10:1 in light, and clipping it to the text leaves no solid colour to raise; render it as flat text instead. */ html.high-contrast:not(.dark) .shimmer { background: none; - color: var(--color-gray-700); - -webkit-text-fill-color: var(--color-gray-700); + color: var(--color-gray-800); + -webkit-text-fill-color: var(--color-gray-800); } diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index c32ef11c77..3f1360a622 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -268,6 +268,8 @@ 'full width mode', 'haptic feedback', 'hapticfeedback', + 'accessibility mode', + 'accessibilitymode', 'high contrast mode', 'highcontrastmode', 'iframe sandbox allow forms', diff --git a/src/lib/components/common/InterfaceSettings.svelte b/src/lib/components/common/InterfaceSettings.svelte index 2bbaee1cd2..51cef5ee3b 100644 --- a/src/lib/components/common/InterfaceSettings.svelte +++ b/src/lib/components/common/InterfaceSettings.svelte @@ -490,13 +490,13 @@