From 6601ebbac0a9cc93d13e36e3c7a0adaaa1b8ab11 Mon Sep 17 00:00:00 2001 From: Tsahi Matsliah Date: Wed, 16 Sep 2026 16:09:35 +0300 Subject: [PATCH 1/2] fix(banner): key the announcement bar CTA to the app theme #6672 chose the CTA from the bar's ink, so pale bars always got the dark button and deep bars the white one. The product call is the opposite: the bar shows the theme's own primary button, white in dark mode and dark in light mode, on every fill. The only exception is the two neutral fills that flip with the theme (white-pepper and salt), where the theme primary would match the bar, so those invert it. The two ink-specific solid modifiers are gone; `btn-primary-inverted` replaces `btn-on-fill-solid-invert` for the exception. Co-Authored-By: Claude Opus 5 --- .../src/components/PromotionalBanner.tsx | 33 +++++++---- .../shared/src/styles/components/buttons.css | 27 ++------- .../components/AnnouncementBar.stories.tsx | 55 ++++++++++--------- 3 files changed, 56 insertions(+), 59 deletions(-) diff --git a/packages/shared/src/components/PromotionalBanner.tsx b/packages/shared/src/components/PromotionalBanner.tsx index 34d7da15e8..2da6c18b8e 100644 --- a/packages/shared/src/components/PromotionalBanner.tsx +++ b/packages/shared/src/components/PromotionalBanner.tsx @@ -15,14 +15,18 @@ import { useViewSize, ViewSize } from '../hooks/useViewSize'; type Ink = 'white' | 'pepper' | 'invert' | 'theme'; -const inkClassNames: Record = { - white: { text: 'text-white', cta: 'btn-on-fill-solid-white' }, - pepper: { text: 'text-raw-pepper-90', cta: 'btn-on-fill-solid-pepper' }, - invert: { text: 'text-surface-invert', cta: 'btn-on-fill-solid-invert' }, - theme: { text: 'text-text-primary' }, +const inkClassNames: Record = { + white: 'text-white', + pepper: 'text-raw-pepper-90', + invert: 'text-surface-invert', + theme: 'text-text-primary', }; -const stylesByTheme: Record = { +type ThemeStyle = { fill: string; ink: Ink; invertedCta?: boolean }; + +// The CTA is the theme's primary button; only the neutral fills that flip +// with the theme (white in dark mode, dark in light mode) invert it. +const stylesByTheme: Record = { [BannerCustomTheme.CabbageOnion]: { fill: 'from-accent-cabbage-subtler to-accent-onion-subtler bg-gradient-to-r', ink: 'invert', @@ -30,6 +34,7 @@ const stylesByTheme: Record = { [BannerCustomTheme.WhitePepper]: { fill: 'bg-surface-primary', ink: 'invert', + invertedCta: true, }, [Theme.Avocado]: { fill: 'bg-accent-avocado-default', ink: 'pepper' }, [Theme.Bacon]: { fill: 'bg-accent-bacon-default', ink: 'pepper' }, @@ -42,7 +47,11 @@ const stylesByTheme: Record = { [Theme.Lettuce]: { fill: 'bg-accent-lettuce-default', ink: 'pepper' }, [Theme.Onion]: { fill: 'bg-accent-onion-default', ink: 'white' }, [Theme.Water]: { fill: 'bg-accent-water-default', ink: 'invert' }, - [Theme.Salt]: { fill: 'bg-accent-salt-default', ink: 'invert' }, + [Theme.Salt]: { + fill: 'bg-accent-salt-default', + ink: 'invert', + invertedCta: true, + }, [Theme.Pepper]: { fill: 'bg-accent-pepper-default', ink: 'theme' }, [Theme.Background]: { fill: 'bg-background-default', ink: 'theme' }, }; @@ -60,10 +69,9 @@ export function PromotionalBannerView({ onDismiss, className, }: PromotionalBannerViewProps): ReactElement { - const { fill, ink } = + const { fill, ink, invertedCta } = stylesByTheme[banner.theme] ?? stylesByTheme[BannerCustomTheme.CabbageOnion]; - const { text, cta } = inkClassNames[ink]; const isLaptop = useViewSize(ViewSize.Laptop); const buttonSize = isLaptop ? ButtonSize.XSmall : ButtonSize.Small; @@ -72,7 +80,7 @@ export function PromotionalBannerView({ className={classNames( 'relative z-3 flex w-full flex-col items-start py-3 pl-3 pr-12 typo-footnote tablet:pl-20 laptop:fixed laptop:h-8 laptop:flex-row laptop:items-center laptop:justify-center laptop:px-10 laptop:py-0', fill, - text, + inkClassNames[ink], className, )} > @@ -84,7 +92,10 @@ export function PromotionalBannerView({ href={banner.url} size={buttonSize} variant={ButtonVariant.Primary} - className={classNames('mt-2 laptop:ml-4 laptop:mt-0', cta)} + className={classNames( + 'mt-2 laptop:ml-4 laptop:mt-0', + invertedCta && 'btn-primary-inverted', + )} onClick={onCtaClick} > {banner.cta} diff --git a/packages/shared/src/styles/components/buttons.css b/packages/shared/src/styles/components/buttons.css index 467e478fb9..f6243c206c 100644 --- a/packages/shared/src/styles/components/buttons.css +++ b/packages/shared/src/styles/components/buttons.css @@ -157,29 +157,12 @@ } /* - * Solid CTA on a brand fill: the neutral primary of the theme the fill's - * ink implies, so a pale bar gets the dark button and a deep bar the - * white one whatever the app theme. `-invert` is for fills painted with - * `bg-surface-primary`, which flip with the theme. + * The neutral primary of the opposite theme, for a fill painted with + * `bg-surface-primary` (white in dark mode, dark in light mode) where the + * theme's own primary would match the fill. */ - &.btn-on-fill-solid-white, - .invert &.btn-on-fill-solid-white { - --button-default-color: var(--btn-label-on-fill-dark); - --button-default-background: theme('colors.white'); - --button-hover-background: theme('colors.raw.salt.30'); - --button-active-background: theme('colors.raw.salt.50'); - } - - &.btn-on-fill-solid-pepper, - .invert &.btn-on-fill-solid-pepper { - --button-default-color: var(--btn-label-on-fill-light); - --button-default-background: theme('colors.raw.pepper.90'); - --button-hover-background: theme('colors.raw.pepper.70'); - --button-active-background: theme('colors.raw.pepper.50'); - } - - &.btn-on-fill-solid-invert, - .invert &.btn-on-fill-solid-invert { + &.btn-primary-inverted, + .invert &.btn-primary-inverted { --button-default-color: var(--theme-surface-primary); --button-default-background: var(--theme-surface-invert); --button-hover-background: color-mix(in srgb, var(--theme-surface-invert), var(--theme-surface-primary) 12%); diff --git a/packages/storybook/stories/components/AnnouncementBar.stories.tsx b/packages/storybook/stories/components/AnnouncementBar.stories.tsx index c5d3702c06..43de8e2869 100644 --- a/packages/storybook/stories/components/AnnouncementBar.stories.tsx +++ b/packages/storybook/stories/components/AnnouncementBar.stories.tsx @@ -45,12 +45,12 @@ const themes: ThemeEntry[] = [ { theme: BannerCustomTheme.WhitePepper, label: 'white-pepper', - note: 'CTA is now the neutral primary of the opposite theme: dark button on the white bar, white button on the dark one. Was the cabbage brand button.', + note: 'CTA is the neutral primary of the opposite theme: dark button on the white bar in dark mode, white button on the dark bar in light mode. Was the cabbage brand button.', }, { theme: Theme.Avocado, label: 'avocado', - note: 'Ink unchanged. CTA is now always the dark button; the white one had 1.7:1 against the fill in dark theme.', + note: 'Ink unchanged. CTA follows the app theme: white in dark mode, dark in light mode.', }, { theme: Theme.Bacon, @@ -60,7 +60,7 @@ const themes: ThemeEntry[] = [ { theme: Theme.BlueCheese, label: 'blue-cheese', - note: 'Ink unchanged. CTA is now always the dark button (was 1.7:1 in dark theme).', + note: 'Ink unchanged. CTA follows the app theme.', }, { theme: Theme.Bun, @@ -80,7 +80,7 @@ const themes: ThemeEntry[] = [ { theme: Theme.Cheese, label: 'cheese', - note: 'Ink unchanged. CTA is now always the dark button (was 1.3:1 in dark theme).', + note: 'Ink unchanged. CTA follows the app theme.', }, { theme: Theme.Ketchup, @@ -90,7 +90,7 @@ const themes: ThemeEntry[] = [ { theme: Theme.Lettuce, label: 'lettuce', - note: 'Ink unchanged. CTA is now always the dark button (was 1.3:1 in dark theme).', + note: 'Ink unchanged. CTA follows the app theme.', }, { theme: Theme.Onion, @@ -108,7 +108,7 @@ const themes: ThemeEntry[] = [ theme: Theme.Salt, label: 'salt', isNew: true, - note: 'New neutral that stands out from the app: light gray in dark theme, dark gray in light theme, like white-pepper but softer.', + note: 'New neutral that stands out from the app: light gray in dark theme, dark gray in light theme, like white-pepper but softer, and the CTA inverts the same way.', }, { theme: Theme.Pepper, @@ -314,46 +314,49 @@ const contrast = (a: string, b: string): number => { type Swatch = { fills: string[]; ink: string; cta: string }; // What each theme resolves to per app theme: bar fill, text ink, CTA fill. +// The CTA is the theme's primary (white in dark, dark in light) except on +// the neutral fills that flip with the theme, where it is inverted. const resolve = (theme: BannerTheme, mode: CanvasTheme): Swatch => { const shade = mode === 'dark' ? '40' : '60'; + const themeCta = mode === 'dark' ? WHITE : PEPPER; + const invertedCta = mode === 'dark' ? PEPPER : WHITE; const white = (name: string): Swatch => ({ fills: [palette[name][shade]], ink: WHITE, - cta: WHITE, + cta: themeCta, }); const pepper = (name: string): Swatch => ({ fills: [palette[name][shade]], ink: PEPPER, - cta: PEPPER, + cta: themeCta, }); // Flipping ink: dark text in dark theme, white in light theme. - const invert = (fills: string[]): Swatch => - mode === 'dark' - ? { fills, ink: PEPPER, cta: PEPPER } - : { fills, ink: WHITE, cta: WHITE }; + const invert = (fills: string[], cta = themeCta): Swatch => + mode === 'dark' ? { fills, ink: PEPPER, cta } : { fills, ink: WHITE, cta }; switch (theme) { case BannerCustomTheme.CabbageOnion: { const subtler = mode === 'dark' ? '20' : '80'; return invert([palette.cabbage[subtler], palette.onion[subtler]]); } case BannerCustomTheme.WhitePepper: - return invert([mode === 'dark' ? WHITE : PEPPER]); + return invert([mode === 'dark' ? WHITE : PEPPER], invertedCta); case Theme.Salt: - return invert([ - mode === 'dark' ? palette.salt['90'] : palette.pepper['10'], - ]); + return invert( + [mode === 'dark' ? palette.salt['90'] : palette.pepper['10']], + invertedCta, + ); case Theme.Cabbage: case Theme.Ketchup: case Theme.Water: return invert([palette[theme][shade]]); case Theme.Pepper: return mode === 'dark' - ? { fills: [palette.pepper['10']], ink: WHITE, cta: WHITE } - : { fills: [palette.salt['90']], ink: PEPPER, cta: PEPPER }; + ? { fills: [palette.pepper['10']], ink: WHITE, cta: themeCta } + : { fills: [palette.salt['90']], ink: PEPPER, cta: themeCta }; case Theme.Background: return mode === 'dark' - ? { fills: [PEPPER], ink: WHITE, cta: WHITE } - : { fills: [WHITE], ink: PEPPER, cta: PEPPER }; + ? { fills: [PEPPER], ink: WHITE, cta: themeCta } + : { fills: [WHITE], ink: PEPPER, cta: themeCta }; case Theme.BlueCheese: return pepper('blueCheese'); case Theme.Avocado: @@ -612,11 +615,11 @@ export const Brief: StoryObj = { fills. It now takes the bar's own text color on every theme.
  • - CTA. It followed the app theme (white button in - dark, dark button in light), which put a white button on the white - bar and on the pale fills. It now follows the bar: pale bar, dark - button; deep bar, white button; white-pepper flips with the theme. - No more brand-colored button on white-pepper. + CTA. The theme's primary button on every + bar: white in dark mode, dark in light mode. The two neutral fills + that flip with the theme (white-pepper and salt) invert it so it + never matches the bar. No more brand-colored button on + white-pepper.
  • Ink. Bun and bacon move to dark text, matching @@ -686,7 +689,7 @@ export const BeforeAfter: StoryObj = {
    {(mode) => ( From bc7accdff36f297100b9969f3fd116d43b65ef74 Mon Sep 17 00:00:00 2001 From: Tsahi Matsliah Date: Wed, 16 Sep 2026 16:15:33 +0300 Subject: [PATCH 2/2] fix(banner): keep the white CTA on white-ink bars in light mode In light mode the bars whose text is white (the purples, blue, red and brown) read better with the white primary than the dark one, and the white button clears 4.9:1 or more against every one of those fills. The pale bars keep the theme's dark button there since white would sit at 1.4-2.9:1 against them. Adds a `white` CTA mode (`btn-primary-white`) next to `theme` and `inverted`. Co-Authored-By: Claude Opus 5 --- .../src/components/PromotionalBanner.tsx | 98 +++++++++++++++---- .../shared/src/styles/components/buttons.css | 12 +++ .../components/AnnouncementBar.stories.tsx | 44 +++++---- 3 files changed, 113 insertions(+), 41 deletions(-) diff --git a/packages/shared/src/components/PromotionalBanner.tsx b/packages/shared/src/components/PromotionalBanner.tsx index 2da6c18b8e..4d50f4b8b6 100644 --- a/packages/shared/src/components/PromotionalBanner.tsx +++ b/packages/shared/src/components/PromotionalBanner.tsx @@ -22,38 +22,96 @@ const inkClassNames: Record = { theme: 'text-text-primary', }; -type ThemeStyle = { fill: string; ink: Ink; invertedCta?: boolean }; +// `theme`: the app theme's primary. `white`: always the white primary, for +// fills whose text is white in both modes. `inverted`: the opposite theme's +// primary, for the neutral fills that flip with the theme. +type Cta = 'theme' | 'white' | 'inverted'; + +const ctaClassNames: Record = { + theme: undefined, + white: 'btn-primary-white', + inverted: 'btn-primary-inverted', +}; + +type ThemeStyle = { fill: string; ink: Ink; cta: Cta }; -// The CTA is the theme's primary button; only the neutral fills that flip -// with the theme (white in dark mode, dark in light mode) invert it. const stylesByTheme: Record = { [BannerCustomTheme.CabbageOnion]: { fill: 'from-accent-cabbage-subtler to-accent-onion-subtler bg-gradient-to-r', ink: 'invert', + cta: 'white', }, [BannerCustomTheme.WhitePepper]: { fill: 'bg-surface-primary', ink: 'invert', - invertedCta: true, + cta: 'inverted', + }, + [Theme.Avocado]: { + fill: 'bg-accent-avocado-default', + ink: 'pepper', + cta: 'theme', + }, + [Theme.Bacon]: { + fill: 'bg-accent-bacon-default', + ink: 'pepper', + cta: 'theme', + }, + [Theme.BlueCheese]: { + fill: 'bg-accent-blueCheese-default', + ink: 'pepper', + cta: 'theme', + }, + [Theme.Bun]: { fill: 'bg-accent-bun-default', ink: 'pepper', cta: 'theme' }, + [Theme.Burger]: { + fill: 'bg-accent-burger-default', + ink: 'white', + cta: 'white', + }, + [Theme.Cabbage]: { + fill: 'bg-accent-cabbage-default', + ink: 'invert', + cta: 'white', + }, + [Theme.Cheese]: { + fill: 'bg-accent-cheese-default', + ink: 'pepper', + cta: 'theme', + }, + [Theme.Ketchup]: { + fill: 'bg-accent-ketchup-default', + ink: 'invert', + cta: 'white', + }, + [Theme.Lettuce]: { + fill: 'bg-accent-lettuce-default', + ink: 'pepper', + cta: 'theme', + }, + [Theme.Onion]: { + fill: 'bg-accent-onion-default', + ink: 'white', + cta: 'white', + }, + [Theme.Water]: { + fill: 'bg-accent-water-default', + ink: 'invert', + cta: 'white', }, - [Theme.Avocado]: { fill: 'bg-accent-avocado-default', ink: 'pepper' }, - [Theme.Bacon]: { fill: 'bg-accent-bacon-default', ink: 'pepper' }, - [Theme.BlueCheese]: { fill: 'bg-accent-blueCheese-default', ink: 'pepper' }, - [Theme.Bun]: { fill: 'bg-accent-bun-default', ink: 'pepper' }, - [Theme.Burger]: { fill: 'bg-accent-burger-default', ink: 'white' }, - [Theme.Cabbage]: { fill: 'bg-accent-cabbage-default', ink: 'invert' }, - [Theme.Cheese]: { fill: 'bg-accent-cheese-default', ink: 'pepper' }, - [Theme.Ketchup]: { fill: 'bg-accent-ketchup-default', ink: 'invert' }, - [Theme.Lettuce]: { fill: 'bg-accent-lettuce-default', ink: 'pepper' }, - [Theme.Onion]: { fill: 'bg-accent-onion-default', ink: 'white' }, - [Theme.Water]: { fill: 'bg-accent-water-default', ink: 'invert' }, [Theme.Salt]: { fill: 'bg-accent-salt-default', ink: 'invert', - invertedCta: true, + cta: 'inverted', + }, + [Theme.Pepper]: { + fill: 'bg-accent-pepper-default', + ink: 'theme', + cta: 'theme', + }, + [Theme.Background]: { + fill: 'bg-background-default', + ink: 'theme', + cta: 'theme', }, - [Theme.Pepper]: { fill: 'bg-accent-pepper-default', ink: 'theme' }, - [Theme.Background]: { fill: 'bg-background-default', ink: 'theme' }, }; export type PromotionalBannerViewProps = { @@ -69,7 +127,7 @@ export function PromotionalBannerView({ onDismiss, className, }: PromotionalBannerViewProps): ReactElement { - const { fill, ink, invertedCta } = + const { fill, ink, cta } = stylesByTheme[banner.theme] ?? stylesByTheme[BannerCustomTheme.CabbageOnion]; const isLaptop = useViewSize(ViewSize.Laptop); @@ -94,7 +152,7 @@ export function PromotionalBannerView({ variant={ButtonVariant.Primary} className={classNames( 'mt-2 laptop:ml-4 laptop:mt-0', - invertedCta && 'btn-primary-inverted', + ctaClassNames[cta], )} onClick={onCtaClick} > diff --git a/packages/shared/src/styles/components/buttons.css b/packages/shared/src/styles/components/buttons.css index f6243c206c..42e9ae960e 100644 --- a/packages/shared/src/styles/components/buttons.css +++ b/packages/shared/src/styles/components/buttons.css @@ -156,6 +156,18 @@ --button-active-background: color-mix(in srgb, currentColor, transparent 72%); } + /* + * The neutral primary pinned to its white form, for a brand fill whose + * text is white in both modes so the button stays on the same ink. + */ + &.btn-primary-white, + .invert &.btn-primary-white { + --button-default-color: var(--btn-label-on-fill-dark); + --button-default-background: theme('colors.white'); + --button-hover-background: theme('colors.raw.salt.30'); + --button-active-background: theme('colors.raw.salt.50'); + } + /* * The neutral primary of the opposite theme, for a fill painted with * `bg-surface-primary` (white in dark mode, dark in light mode) where the diff --git a/packages/storybook/stories/components/AnnouncementBar.stories.tsx b/packages/storybook/stories/components/AnnouncementBar.stories.tsx index 43de8e2869..303746f812 100644 --- a/packages/storybook/stories/components/AnnouncementBar.stories.tsx +++ b/packages/storybook/stories/components/AnnouncementBar.stories.tsx @@ -40,7 +40,7 @@ const themes: ThemeEntry[] = [ { theme: BannerCustomTheme.CabbageOnion, label: 'cabbage-onion (default)', - note: 'Moved from the -default to the -subtler shades with flipping ink: dark text on a lighter gradient in dark theme, white on a deeper one in light theme. At -default no ink passed AA at both ends in dark theme (white 3.8 at the cabbage end, dark 3.6 at the onion end).', + note: 'Moved from the -default to the -subtler shades with flipping ink: dark text on a lighter gradient in dark theme, white on a deeper one in light theme. At -default no ink passed AA at both ends in dark theme. White button in both modes (6.3 against the cabbage end in light mode).', }, { theme: BannerCustomTheme.WhitePepper, @@ -50,59 +50,59 @@ const themes: ThemeEntry[] = [ { theme: Theme.Avocado, label: 'avocado', - note: 'Ink unchanged. CTA follows the app theme: white in dark mode, dark in light mode.', + note: 'Ink unchanged. CTA follows the app theme: white in dark mode, dark in light mode (white would be 2.0 against the fill there).', }, { theme: Theme.Bacon, label: 'bacon', - note: 'Proposed: dark ink. White text was 3.2:1 in dark theme; the button system already puts a dark label on bacon fills.', + note: 'Proposed: dark ink. White text was 3.2:1 in dark theme; the button system already puts a dark label on bacon fills. CTA follows the app theme, matching the dark text in light mode.', }, { theme: Theme.BlueCheese, label: 'blue-cheese', - note: 'Ink unchanged. CTA follows the app theme.', + note: 'Ink unchanged. CTA follows the app theme (white would be 2.1 in light mode).', }, { theme: Theme.Bun, label: 'bun', - note: 'Proposed: dark ink. White text was 2.2:1 in dark theme, the worst pair on the list; the button system already puts a dark label on bun fills.', + note: 'Proposed: dark ink. White text was 2.2:1 in dark theme, the worst pair on the list; the button system already puts a dark label on bun fills. CTA follows the app theme (white would be 2.9 in light mode).', }, { theme: Theme.Burger, label: 'burger', - note: 'Unchanged. White passes in both themes (4.6 / 6.3); dark ink would drop to 4.1 in dark theme.', + note: 'Unchanged ink: white passes in both themes (4.6 / 6.3). White button in both modes.', }, { theme: Theme.Cabbage, label: 'cabbage', - note: 'Flipping ink: dark text in dark theme, white in light. White text was 3.8:1 in dark theme and no dark-theme shade of cabbage reaches 4.5 with white; dark text on -default does (4.9).', + note: 'Flipping ink: dark text in dark theme, white in light. White text was 3.8:1 in dark theme and no dark-theme shade of cabbage reaches 4.5 with white; dark text on -default does (4.9). White button in both modes (4.9 in light).', }, { theme: Theme.Cheese, label: 'cheese', - note: 'Ink unchanged. CTA follows the app theme.', + note: 'Ink unchanged. CTA follows the app theme (white would be 1.4 in light mode).', }, { theme: Theme.Ketchup, label: 'ketchup', - note: 'Flipping ink, same reasoning as cabbage: white text was 3.9:1 in dark theme; dark text on -default is 4.8.', + note: 'Flipping ink, same reasoning as cabbage: white text was 3.9:1 in dark theme; dark text on -default is 4.8. White button in both modes (5.1 in light).', }, { theme: Theme.Lettuce, label: 'lettuce', - note: 'Ink unchanged. CTA follows the app theme.', + note: 'Ink unchanged. CTA follows the app theme (white would be 1.5 in light mode).', }, { theme: Theme.Onion, label: 'onion', isNew: true, - note: 'New. White ink passes in both themes (5.2 / 7.1), the strongest of the saturated set.', + note: 'New. White ink passes in both themes (5.2 / 7.1), the strongest of the saturated set. White button in both modes.', }, { theme: Theme.Water, label: 'water', isNew: true, - note: 'New. Flipping ink like cabbage: white would be 3.8:1 in dark theme, dark text on -default is 4.9; light theme keeps white at 5.1.', + note: 'New. Flipping ink like cabbage: white would be 3.8:1 in dark theme, dark text on -default is 4.9; light theme keeps white at 5.1. White button in both modes.', }, { theme: Theme.Salt, @@ -314,8 +314,9 @@ const contrast = (a: string, b: string): number => { type Swatch = { fills: string[]; ink: string; cta: string }; // What each theme resolves to per app theme: bar fill, text ink, CTA fill. -// The CTA is the theme's primary (white in dark, dark in light) except on -// the neutral fills that flip with the theme, where it is inverted. +// The CTA is the theme's primary (white in dark, dark in light) on dark-ink +// fills, always white on white-ink fills, and inverted on the neutral fills +// that flip with the theme. const resolve = (theme: BannerTheme, mode: CanvasTheme): Swatch => { const shade = mode === 'dark' ? '40' : '60'; const themeCta = mode === 'dark' ? WHITE : PEPPER; @@ -323,7 +324,7 @@ const resolve = (theme: BannerTheme, mode: CanvasTheme): Swatch => { const white = (name: string): Swatch => ({ fills: [palette[name][shade]], ink: WHITE, - cta: themeCta, + cta: WHITE, }); const pepper = (name: string): Swatch => ({ fills: [palette[name][shade]], @@ -331,7 +332,7 @@ const resolve = (theme: BannerTheme, mode: CanvasTheme): Swatch => { cta: themeCta, }); // Flipping ink: dark text in dark theme, white in light theme. - const invert = (fills: string[], cta = themeCta): Swatch => + const invert = (fills: string[], cta = WHITE): Swatch => mode === 'dark' ? { fills, ink: PEPPER, cta } : { fills, ink: WHITE, cta }; switch (theme) { case BannerCustomTheme.CabbageOnion: { @@ -615,11 +616,12 @@ export const Brief: StoryObj = { fills. It now takes the bar's own text color on every theme.
  • - CTA. The theme's primary button on every - bar: white in dark mode, dark in light mode. The two neutral fills - that flip with the theme (white-pepper and salt) invert it so it - never matches the bar. No more brand-colored button on - white-pepper. + CTA. White in dark mode on every bar. In light + mode it stays white on the bars whose text is white (the purples, + blue, red, brown) and goes dark on the pale bars whose text is + dark. The two neutral fills that flip with the theme (white-pepper + and salt) invert it so it never matches the bar. No more + brand-colored button on white-pepper.
  • Ink. Bun and bacon move to dark text, matching