diff --git a/data/menuItems.ts b/data/menuItems.ts index a5f228ee..5ad18e5e 100644 --- a/data/menuItems.ts +++ b/data/menuItems.ts @@ -64,7 +64,7 @@ export const menuItems: MenuItem[] = [ header: { title: 'AI Professionals', subtitle: 'Expert advisors for every need', - gradient: 'bg-gradient-to-r from-blue-50 to-purple-50', + gradient: 'bg-action-tint', }, }, }, diff --git a/data/professionals.ts b/data/professionals.ts index 58155130..5d125be1 100644 --- a/data/professionals.ts +++ b/data/professionals.ts @@ -334,64 +334,21 @@ export const professionalCategories = { } as const; /** - * Get accent color class for Tailwind + * Accent classes for a first-party professional. + * + * There is one scheme, because there is one brand. These six ARE Botsmann, so + * they wear the identity defined in app/globals.css rather than a per-person + * colour -- a blue Lex beside an ochre CTA was the whole problem. + * + * The `color` argument is kept so callers and the data shape stay unchanged; + * it no longer selects a palette. */ -export const getAccentColorClasses = (color: ProfessionalAccentColor) => { - const colors = { - blue: { - bg: 'bg-blue-500', - bgLight: 'bg-blue-100', - bgGradient: 'from-blue-500 to-blue-600', - text: 'text-blue-600', - border: 'border-blue-500', - hover: 'hover:bg-blue-600', - groupHoverText: 'group-hover:text-blue-600', - }, - green: { - bg: 'bg-green-500', - bgLight: 'bg-green-100', - bgGradient: 'from-green-500 to-green-600', - text: 'text-green-600', - border: 'border-green-500', - hover: 'hover:bg-green-600', - groupHoverText: 'group-hover:text-green-600', - }, - indigo: { - bg: 'bg-indigo-500', - bgLight: 'bg-indigo-100', - bgGradient: 'from-indigo-500 to-indigo-600', - text: 'text-indigo-600', - border: 'border-indigo-500', - hover: 'hover:bg-indigo-600', - groupHoverText: 'group-hover:text-indigo-600', - }, - red: { - bg: 'bg-red-500', - bgLight: 'bg-red-100', - bgGradient: 'from-red-500 to-red-600', - text: 'text-red-600', - border: 'border-red-500', - hover: 'hover:bg-red-600', - groupHoverText: 'group-hover:text-red-600', - }, - amber: { - bg: 'bg-amber-500', - bgLight: 'bg-amber-100', - bgGradient: 'from-amber-500 to-amber-600', - text: 'text-amber-600', - border: 'border-amber-500', - hover: 'hover:bg-amber-600', - groupHoverText: 'group-hover:text-amber-600', - }, - purple: { - bg: 'bg-purple-500', - bgLight: 'bg-purple-100', - bgGradient: 'from-purple-500 to-purple-600', - text: 'text-purple-600', - border: 'border-purple-500', - hover: 'hover:bg-purple-600', - groupHoverText: 'group-hover:text-purple-600', - }, - }; - return colors[color]; -}; +export const getAccentColorClasses = (_color?: ProfessionalAccentColor) => ({ + bg: 'bg-action', + bgLight: 'bg-action-tint', + bgGradient: 'from-action to-action-hover', + text: 'text-action', + border: 'border-action', + hover: 'hover:bg-action-hover', + groupHoverText: 'group-hover:text-action', +}); diff --git a/tests/__tests__/lib/design-tokens.test.ts b/tests/__tests__/lib/design-tokens.test.ts index e0be795f..b2b539c7 100644 --- a/tests/__tests__/lib/design-tokens.test.ts +++ b/tests/__tests__/lib/design-tokens.test.ts @@ -37,8 +37,19 @@ const CUSTOM_BOT_SURFACES = [ join('lib', 'config', 'colors.ts'), ]; -/** Semantic status colours are a separate scale from the brand accent. */ -const SEMANTIC_FILES = [join('components', 'knowledge', 'Callout.tsx')]; +/** + * Categorical and semantic scales, which are NOT the brand accent. + * + * A status scale has to stay mutually distinguishable: recolouring + * "processing" to ochre would make it read as brand chrome rather than state. + * Same for provider identity, which exists so you can tell Ollama from OpenAI + * at a glance. Each entry is an exception with a reason, not a to-do. + */ +const SEMANTIC_FILES = [ + join('components', 'knowledge', 'Callout.tsx'), // info / warning / error + join('lib', 'constants.ts'), // document status: pending / processing / ready / error + join('lib', 'infrastructure', 'providers.ts'), // per-provider identity colours +]; function tsxFiles(dir: string): string[] { const out: string[] = []; @@ -59,7 +70,15 @@ function isAllowed(rel: string): boolean { } describe('design tokens', () => { - const files = [...tsxFiles(join(ROOT, 'app')), ...tsxFiles(join(ROOT, 'components'))]; + // data/ and lib/ too: the palette hid in data/professionals.ts for a whole + // sweep because the first version of this guard only looked at app/ and + // components/. A scanner is blind in exactly the shapes it forgets to read. + const files = [ + ...tsxFiles(join(ROOT, 'app')), + ...tsxFiles(join(ROOT, 'components')), + ...tsxFiles(join(ROOT, 'data')), + ...tsxFiles(join(ROOT, 'lib')), + ]; it('scans a meaningful number of files', () => { expect(files.length).toBeGreaterThan(100);