authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-01 22:28:43-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-01 22:28:43-04:00
log8401f4d85887786fbb773d3fd41b8f07a77624b8
tree5bd9f32a5c620774acbb473235095d6676e1559c
parent0e1570bde5b64458449a45989f1b56d6fd651883
signature Signed by PGP key B5690EEEBB952194

fix(web): darken neutral control surfaces (#9064)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

5 files changed, 28 insertions(+), 14 deletions(-)

apps/web/src/components/chat/ComposerBanner.tsx+1-1
...@@ -11,7 +11,7 @@ export type ComposerBannerVariant = "default" | "error" | "info" | "success" | "...@@ -11,7 +11,7 @@ export type ComposerBannerVariant = "default" | "error" | "info" | "success" | "
1111
12const surfaceColors = cn(12const surfaceColors = cn(
13 "[--chat-composer-attached-surface:var(--chat-composer-glass-surface,var(--card))]",13 "[--chat-composer-attached-surface:var(--chat-composer-glass-surface,var(--card))]",
14 "dark:[--chat-composer-attached-surface:var(--chat-composer-glass-surface,color-mix(in_srgb,var(--background)_96%,var(--color-white)))]",14 "dark:[--chat-composer-attached-surface:var(--chat-composer-glass-surface,var(--surface-raised))]",
15 "[html[data-theme-id]_&]:[--chat-composer-attached-surface:var(--app-theme-surface-raised)]",15 "[html[data-theme-id]_&]:[--chat-composer-attached-surface:var(--app-theme-surface-raised)]",
16);16);
1717
apps/web/src/components/chat/ComposerSurface.tsx+2-2
...@@ -15,7 +15,7 @@ function Shell({...@@ -15,7 +15,7 @@ function Shell({
15 className={cn(15 className={cn(
16 "group/composer-surface relative isolate mx-auto w-full max-w-3xl",16 "group/composer-surface relative isolate mx-auto w-full max-w-3xl",
17 "[--chat-composer-drawer-inset:1.375rem] [--chat-composer-glass-surface:var(--card)] [--chat-composer-outline:rgb(0_0_0/8%)]",17 "[--chat-composer-drawer-inset:1.375rem] [--chat-composer-glass-surface:var(--card)] [--chat-composer-outline:rgb(0_0_0/8%)]",
18 "dark:[--chat-composer-glass-surface:color-mix(in_srgb,var(--background)_96%,var(--color-white))] dark:[--chat-composer-highlight:rgb(255_255_255/3%)] dark:[--chat-composer-outline:color-mix(in_srgb,var(--color-white)_5%,transparent)]",18 "dark:[--chat-composer-glass-surface:var(--surface-raised)] dark:[--chat-composer-highlight:rgb(255_255_255/3%)] dark:[--chat-composer-outline:color-mix(in_srgb,var(--color-white)_5%,transparent)]",
19 "[html[data-theme-id]_&]:[--chat-composer-glass-surface:var(--app-theme-surface-raised)] [html[data-theme-id]_&]:[--chat-composer-outline:var(--app-theme-toolbar-border)]",19 "[html[data-theme-id]_&]:[--chat-composer-glass-surface:var(--app-theme-surface-raised)] [html[data-theme-id]_&]:[--chat-composer-outline:var(--app-theme-toolbar-border)]",
20 "dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-highlight:color-mix(in_srgb,var(--app-theme-input)_12%,transparent)] dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-outline:color-mix(in_srgb,var(--app-theme-input)_30%,var(--background))]",20 "dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-highlight:color-mix(in_srgb,var(--app-theme-input)_12%,transparent)] dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-outline:color-mix(in_srgb,var(--app-theme-input)_30%,var(--background))]",
21 "dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-highlight:color-mix(in_srgb,#432d48_12%,transparent)] dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-outline:#241e28]",21 "dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-highlight:color-mix(in_srgb,#432d48_12%,transparent)] dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-outline:#241e28]",
...@@ -86,7 +86,7 @@ function ContextStrip({ className, ...props }: ComponentProps<"div">) {...@@ -86,7 +86,7 @@ function ContextStrip({ className, ...props }: ComponentProps<"div">) {
86 className={cn(86 className={cn(
87 "group/composer-context relative isolate mx-auto -mt-4 flex w-[calc(100%-2*var(--chat-composer-drawer-inset))] items-center gap-2 overflow-x-clip overflow-y-visible ps-1 pe-2 pt-5 pb-1",87 "group/composer-context relative isolate mx-auto -mt-4 flex w-[calc(100%-2*var(--chat-composer-drawer-inset))] items-center gap-2 overflow-x-clip overflow-y-visible ps-1 pe-2 pt-5 pb-1",
88 "before:absolute before:inset-0 before:-z-1 before:rounded-b-[16px] before:border before:border-(--chat-composer-outline) before:mask-[linear-gradient(to_bottom,transparent_0_1rem,black_1rem)] before:shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)]",88 "before:absolute before:inset-0 before:-z-1 before:rounded-b-[16px] before:border before:border-(--chat-composer-outline) before:mask-[linear-gradient(to_bottom,transparent_0_1rem,black_1rem)] before:shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)]",
89 "dark:before:border-white/7 dark:before:bg-[linear-gradient(to_bottom,transparent_0_1rem,rgb(0_0_0/18%)_1rem,transparent_calc(1rem+10px)),linear-gradient(rgb(255_255_255/2%),rgb(255_255_255/2%))] dark:before:shadow-[0_14px_32px_-18px_rgb(0_0_0/75%)]",89 "dark:before:border-white/7 dark:before:bg-[linear-gradient(to_bottom,transparent_0_1rem,rgb(0_0_0/18%)_1rem,transparent_calc(1rem+10px)),linear-gradient(rgb(255_255_255/1%),rgb(255_255_255/1%))] dark:before:shadow-[0_14px_32px_-18px_rgb(0_0_0/75%)]",
90 "group-has-data-[composer-banner-surface=attached]/composer-surface:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-saturate-(--glass-saturation)",90 "group-has-data-[composer-banner-surface=attached]/composer-surface:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-saturate-(--glass-saturation)",
91 "not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-blur-(--glass-blur) not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-saturate-(--glass-saturation)",91 "not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-blur-(--glass-blur) not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-saturate-(--glass-saturation)",
92 className,92 className,
apps/web/src/index.css+6-6
...@@ -979,19 +979,19 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil...@@ -979,19 +979,19 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil
979979
980 @variant dark {980 @variant dark {
981 color-scheme: dark;981 color-scheme: dark;
982 /* Keep the workspace in the same neutral-black family as sidebar v2.982 /* Keep controls and floating surfaces close to the neutral-black canvas.
983 Surfaces lift from this base instead of starting from a milky gray. */983 Borders and hover states provide separation without milky gray fills. */
984 --background: var(--color-neutral-950);984 --background: var(--color-neutral-950);
985 --surface-raised: var(--secondary);985 --surface-raised: color-mix(in srgb, var(--background) 97%, var(--color-white));
986 --foreground: var(--color-neutral-100);986 --foreground: var(--color-neutral-100);
987 --card: color-mix(in srgb, var(--background) 97%, var(--color-white));987 --card: color-mix(in srgb, var(--background) 97%, var(--color-white));
988 --card-foreground: var(--color-neutral-100);988 --card-foreground: var(--color-neutral-100);
989 --popover: color-mix(in srgb, var(--background) 94%, var(--color-white));989 --popover: color-mix(in srgb, var(--background) 97%, var(--color-white));
990 --popover-foreground: var(--color-neutral-100);990 --popover-foreground: var(--color-neutral-100);
991 --primary: oklch(0.571 0.21 264);991 --primary: oklch(0.571 0.21 264);
992 --secondary: --alpha(var(--color-white) / 4%);992 --secondary: --alpha(var(--color-white) / 3%);
993 --secondary-foreground: var(--color-neutral-100);993 --secondary-foreground: var(--color-neutral-100);
994 --muted: --alpha(var(--color-white) / 4%);994 --muted: --alpha(var(--color-white) / 3%);
995 --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-white));995 --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-white));
996 --accent: --alpha(var(--color-white) / 4%);996 --accent: --alpha(var(--color-white) / 4%);
997 --accent-foreground: var(--color-neutral-100);997 --accent-foreground: var(--color-neutral-100);
apps/web/src/themePalette.test.ts+14
...@@ -11,6 +11,7 @@ import {...@@ -11,6 +11,7 @@ import {
11 getThemePreferenceMode,11 getThemePreferenceMode,
12 isKnownThemePreference,12 isKnownThemePreference,
13 getCustomThemes,13 getCustomThemes,
14 getStandardThemeColors,
14 getStoredCustomThemeCollection,15 getStoredCustomThemeCollection,
15 invalidateCustomThemes,16 invalidateCustomThemes,
16 installCustomTheme,17 installCustomTheme,
...@@ -134,6 +135,19 @@ describe("theme files", () => {...@@ -134,6 +135,19 @@ describe("theme files", () => {
134 expect(asHex(dark.error)).not.toBe(asHex(darkDefaults.error));135 expect(asHex(dark.error)).not.toBe(asHex(darkDefaults.error));
135 });136 });
136137
138 it("keeps stock dark controls in the neutral-black surface hierarchy", () => {
139 expectThemeColors(getStandardThemeColors("dark"), {
140 canvas: "#0a0a0a",
141 surface: "#111111",
142 surfaceRaised: "#111111",
143 surfaceOverlay: "#111111",
144 toolbarControl: "#111111",
145 secondary: "#111111",
146 muted: "#111111",
147 accentSurface: "#141414",
148 });
149 });
150
137 it("derives readable, distinctive vivid palettes from exact seeds", () => {151 it("derives readable, distinctive vivid palettes from exact seeds", () => {
138 const seeds: ReadonlyArray<["light" | "dark", string, string]> = [152 const seeds: ReadonlyArray<["light" | "dark", string, string]> = [
139 ["light", "#f4f9f2", "#1d8a4e"],153 ["light", "#f4f9f2", "#1d8a4e"],
apps/web/src/themePalette.ts+5-5
...@@ -402,12 +402,12 @@ const T3_CODE_DARK_THEME_COLORS: ThemeColors = {...@@ -402,12 +402,12 @@ const T3_CODE_DARK_THEME_COLORS: ThemeColors = {
402 toolbar: "#0a0a0a",402 toolbar: "#0a0a0a",
403 toolbarForeground: "#f5f5f5",403 toolbarForeground: "#f5f5f5",
404 toolbarBorder: "#191919",404 toolbarBorder: "#191919",
405 toolbarControl: "#191919",405 toolbarControl: "#111111",
406 toolbarControlForeground: "#f5f5f5",406 toolbarControlForeground: "#f5f5f5",
407 toolbarControlHover: "#141414",407 toolbarControlHover: "#141414",
408 surface: "#111111",408 surface: "#111111",
409 surfaceRaised: "#141414",409 surfaceRaised: "#111111",
410 surfaceOverlay: "#191919",410 surfaceOverlay: "#111111",
411 text: "#f5f5f5",411 text: "#f5f5f5",
412 textMuted: "#818181",412 textMuted: "#818181",
413 border: "#191919",413 border: "#191919",
...@@ -415,9 +415,9 @@ const T3_CODE_DARK_THEME_COLORS: ThemeColors = {...@@ -415,9 +415,9 @@ const T3_CODE_DARK_THEME_COLORS: ThemeColors = {
415 focus: "#346bf1",415 focus: "#346bf1",
416 accent: "#346bf1",416 accent: "#346bf1",
417 accentForeground: "#ffffff",417 accentForeground: "#ffffff",
418 secondary: "#141414",418 secondary: "#111111",
419 secondaryForeground: "#f5f5f5",419 secondaryForeground: "#f5f5f5",
420 muted: "#141414",420 muted: "#111111",
421 mutedForeground: "#818181",421 mutedForeground: "#818181",
422 placeholder: "#818181",422 placeholder: "#818181",
423 secondaryLabel: "#818181",423 secondaryLabel: "#818181",