From 1ac8ef7853bc9f90be75da3688ff8c84f7769178 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 27 Jul 2026 00:57:00 +0200 Subject: [PATCH] fix: gate the remaining text contrast failures behind High Contrast Mode (#27558) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the contrast set after #27555, #27554 and the gray-500 branch, which between them cover text-gray-400, text-gray-500, dark:text-gray-600 and placeholders. This is everything still under 4.5:1 after those. The grey scale in src/tailwind.css is achromatic oklch(L 0 0), so relative luminance is exactly L³. What is left: - text-gray-300 dark:text-gray-700, the lightest muted pair, at 1.58:1 in light and 2.14:1 in dark. Used for inactive tab labels across the admin, workspace and playground layouts, breadcrumb separators and empty state hints. It resolves to gray-600 in light and gray-400 in dark. - text-gray-400/70 on the embedded chat history dropdown icon, 2.07:1 against the 3:1 that WCAG 1.4.11 requires of icons. - Hover states that land lighter than the new resting colour. Once the resting state is gray-600, an element hovering to gray-500 gets less readable on interaction rather than more, so hover and group-hover targets of gray-500 resolve to gray-800. Sidebar/Section.svelte and the citation modal links are the sites this affects. - The autocompletion ghost text in src/app.css, hardcoded #a0a0a0, 2.65:1 in light. The dark canvas already passes. - The shimmer used for loading text, a #b4b4b4 gradient clipped to the glyphs at 2.10:1 in light. There is no solid colour to raise, so with the setting on it renders as flat gray-700 text instead. Everything above is gated on the existing High Contrast Mode setting and changes nothing when it is off. No markup is touched, so this is src/app.css only. Deliberately left alone: disabled: variants, since WCAG 1.4.3 exempts inactive components; the FileNav breadcrumb ancestors, which are non-clickable; decorative folder icons; and text-gray-100, dark:text-gray-800 and dark:text-gray-900, which are inverse text on filled buttons and already high contrast against their own backgrounds. The ad-hoc dark:text-gray-800 pairs in ChannelModal.svelte and automations/+layout.svelte stay as they are; dark:text-gray-800 doubles as the inverse text on the white buttons in Message.svelte, ResponseMessage.svelte and UserMessage.svelte, so it cannot be remapped in CSS without breaking those. Not fixed here, and a genuine follow-up: .hljs-comment in src/app.css is #616161, roughly 3:1 on the dark code background. It sits outside the Tailwind grey scale and needs a highlight.js theme override rather than a utility remap. Verified in a browser against Tailwind's emitted rules and layer order: with the setting on, the lightest pair resolves to gray-600 in light and gray-400 in dark, the hover and group-hover targets to gray-800, ghost text to gray-600 and the shimmer to solid gray-700, while inverse button text and every dark hover variant stay where they are; with the setting off nothing changes in either theme. --- src/app.css | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/app.css b/src/app.css index f0b54219d0..e9e3eef35e 100644 --- a/src/app.css +++ b/src/app.css @@ -884,3 +884,37 @@ body { html.high-contrast:not(.dark) :is(.app-muted, .app-icon-muted, .tiptap table) { color: var(--color-gray-600); } + +/* High Contrast 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); + } + + html:where(.high-contrast).dark .dark\:text-gray-700 { + color: var(--color-gray-400); + } + + /* 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)) .group:hover .group-hover\:text-gray-500 { + color: var(--color-gray-800); + } +} + +/* 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); +} + +/* 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); +}