From 2763531ce4d2b15a47ad447d6acc3177f7d1f1a2 Mon Sep 17 00:00:00 2001 From: karti Date: Thu, 13 Aug 2026 03:17:49 -0700 Subject: [PATCH] Align shadcn's `accent` token with what shadcn means by it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shadcn uses `bg-accent` for its SUBTLE surfaces — dropdown item hover, command row selection, ghost and outline button hover, the dialog close affordance. The brand colour in shadcn is `primary`. PIG's Tailwind config mapped `accent` to `--accent`, which is the brand. That inverted the meaning, so every shadcn hover and selection state painted a full-strength brand block. With the monochrome "pig" palette in dark mode the brand is near-white, so a selected command row rendered as a white slab against a near-black sheet. Measured before the change: selected row rgb(250,250,250) on a rgb(9,9,11) body. `accent` now aliases `--accent-subtle` and `accent-foreground` aliases `--accent-fg`, which is what those tokens were created for. The eleven places where PIG's own components wanted a solid brand fill — filled chips, selected card borders, progress bars — move to `primary`, which still resolves to `--accent`. A `brand` alias is added for clarity. After: selected row rgb(39,39,42) in dark and rgb(244,244,245) in light, both a subtle tint above the body; the pipeline's active stage chip stays a solid rgb(250,250,250) fill, unchanged. Found by opening overlays, which earlier screenshot sweeps never did — every route had been checked, but a dropdown or a command palette only misbehaves once it is open. Worth remembering: page-level sweeps do not exercise portals. Typecheck clean, 135 unit tests and e2e green, CSP hash unchanged, 0px horizontal overflow across 12 routes at 393px and 1440px. Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 8 ++++++++ apps/web/src/components/AdminSettings.tsx | 2 +- apps/web/src/components/AllocationSheet.tsx | 4 ++-- apps/web/src/components/GoogleSheetsSource.tsx | 2 +- apps/web/src/components/PiggyChat.tsx | 2 +- apps/web/src/pages/Capacity.tsx | 4 ++-- apps/web/src/pages/CreateProfile.tsx | 2 +- apps/web/src/pages/FactReview.tsx | 2 +- apps/web/src/pages/Imports.tsx | 2 +- apps/web/src/pages/Pipeline.tsx | 2 +- apps/web/src/pages/Register.tsx | 2 +- apps/web/src/pages/Settings.tsx | 2 +- apps/web/tailwind.config.js | 18 ++++++++++++++++-- 13 files changed, 37 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 314f909..feb4d5c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -140,6 +140,14 @@ conflict on, do an existence check instead. flag set to false was silently on. Use the `envBoolean` helper in `apps/api/src/lib/config.ts`. +**shadcn's `accent` is a SUBTLE surface, not the brand.** shadcn uses +`bg-accent` for hover, focus and selected states — dropdown items, command +rows, ghost buttons. The brand is `primary`. In `tailwind.config.js`, `accent` +is therefore aliased to `--accent-subtle` and `primary` to `--accent`. Use +`bg-primary` for a solid brand fill; never `bg-accent`. Mapping them the other +way makes every hover state paint a full-strength brand block, which in dark +mode with the monochrome palette is a glaring white slab. + **Grid and flex children need `min-w-0`.** They default to `min-width: auto`, meaning they refuse to shrink below their content — and a `tabular-nums` figure, a `whitespace-nowrap` badge or a `truncate` title is all diff --git a/apps/web/src/components/AdminSettings.tsx b/apps/web/src/components/AdminSettings.tsx index 71103a1..4ef6b34 100644 --- a/apps/web/src/components/AdminSettings.tsx +++ b/apps/web/src/components/AdminSettings.tsx @@ -67,7 +67,7 @@ export function AdminSettings() {
-
+
diff --git a/apps/web/src/components/AllocationSheet.tsx b/apps/web/src/components/AllocationSheet.tsx index 2e16205..c65f476 100644 --- a/apps/web/src/components/AllocationSheet.tsx +++ b/apps/web/src/components/AllocationSheet.tsx @@ -526,8 +526,8 @@ function CommitmentContext({ row, detail, match, quotedPrice }: { row: Availabil {match ? 0.7 ? 'positive' : 'neutral'}>{percent(match.score)} fit : null}
-
-
+
+

Sold

{compactNumber(row.soldGpuHours)} hrs

diff --git a/apps/web/src/components/GoogleSheetsSource.tsx b/apps/web/src/components/GoogleSheetsSource.tsx index 104d4d8..1aa91cd 100644 --- a/apps/web/src/components/GoogleSheetsSource.tsx +++ b/apps/web/src/components/GoogleSheetsSource.tsx @@ -137,7 +137,7 @@ export function GoogleSheetsSource({ onLoaded }: { onLoaded(table: GoogleParsedT {files.isLoading ? : files.isError ? : files.data?.files.length === 0 ? : (
{files.data?.files.map((file) => ( - diff --git a/apps/web/src/components/PiggyChat.tsx b/apps/web/src/components/PiggyChat.tsx index 2efd4a5..8afae66 100644 --- a/apps/web/src/components/PiggyChat.tsx +++ b/apps/web/src/components/PiggyChat.tsx @@ -264,7 +264,7 @@ function PiggyChatPanel({ function ChatMessage({ message }: { message: TranscriptMessage }) { if (message.role === 'user') { - return

{message.content}

; + return

{message.content}

; } return (
diff --git a/apps/web/src/pages/Capacity.tsx b/apps/web/src/pages/Capacity.tsx index 26ff986..05a545f 100644 --- a/apps/web/src/pages/Capacity.tsx +++ b/apps/web/src/pages/Capacity.tsx @@ -161,9 +161,9 @@ function CapacityCard({ row, writable, onAllocate }: { row: AvailabilityRow; wri bar made mostly of unconverted holds is a lie a seller would act on. */}
-
+
diff --git a/apps/web/src/pages/CreateProfile.tsx b/apps/web/src/pages/CreateProfile.tsx index 758cb47..d3ced5e 100644 --- a/apps/web/src/pages/CreateProfile.tsx +++ b/apps/web/src/pages/CreateProfile.tsx @@ -95,7 +95,7 @@ export function CreateProfile({ className={[ 'flex cursor-pointer items-start gap-3 rounded-lg border p-3 transition-colors', team === value - ? 'border-accent bg-accent-subtle' + ? 'border-primary bg-accent-subtle' : 'border-border hover:bg-surface-2', ].join(' ')} > diff --git a/apps/web/src/pages/FactReview.tsx b/apps/web/src/pages/FactReview.tsx index f5c9a83..9b39b5c 100644 --- a/apps/web/src/pages/FactReview.tsx +++ b/apps/web/src/pages/FactReview.tsx @@ -99,7 +99,7 @@ export function FactReview() { - +
diff --git a/apps/web/src/pages/Imports.tsx b/apps/web/src/pages/Imports.tsx index e77cc97..5a6af92 100644 --- a/apps/web/src/pages/Imports.tsx +++ b/apps/web/src/pages/Imports.tsx @@ -145,7 +145,7 @@ export function Imports() { type="button" aria-pressed={entity === candidate} onClick={() => resetForEntity(candidate)} - className={entity === candidate ? 'tap card min-w-0 border-accent p-4 text-left ring-1 ring-accent' : 'tap card min-w-0 p-4 text-left'} + className={entity === candidate ? 'tap card min-w-0 border-primary p-4 text-left ring-1 ring-primary' : 'tap card min-w-0 p-4 text-left'} >

{candidateDefinition.label}

{candidateDefinition.description}

diff --git a/apps/web/src/pages/Pipeline.tsx b/apps/web/src/pages/Pipeline.tsx index 39a0acb..e5b83da 100644 --- a/apps/web/src/pages/Pipeline.tsx +++ b/apps/web/src/pages/Pipeline.tsx @@ -184,7 +184,7 @@ function PipelineBoard diff --git a/apps/web/src/pages/Register.tsx b/apps/web/src/pages/Register.tsx index 2a35b37..4583e50 100644 --- a/apps/web/src/pages/Register.tsx +++ b/apps/web/src/pages/Register.tsx @@ -172,7 +172,7 @@ export function Register({ className={[ 'flex cursor-pointer items-start gap-3 rounded-lg border p-3 transition-colors', team === value - ? 'border-accent bg-accent-subtle' + ? 'border-primary bg-accent-subtle' : 'border-border hover:bg-surface-2', ].join(' ')} > diff --git a/apps/web/src/pages/Settings.tsx b/apps/web/src/pages/Settings.tsx index 9d34d09..ada565c 100644 --- a/apps/web/src/pages/Settings.tsx +++ b/apps/web/src/pages/Settings.tsx @@ -93,7 +93,7 @@ function Appearance() { title={option.label} className={[ 'tap relative flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors', - selected ? 'border-accent bg-accent-subtle' : 'border-border hover:bg-surface-2', + selected ? 'border-primary bg-accent-subtle' : 'border-border hover:bg-surface-2', ].join(' ')} > {/* diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js index 61a0260..433e17c 100644 --- a/apps/web/tailwind.config.js +++ b/apps/web/tailwind.config.js @@ -20,8 +20,22 @@ export default { foreground: 'hsl(var(--fg))', muted: 'hsl(var(--muted))', 'muted-foreground': 'hsl(var(--muted))', - accent: 'hsl(var(--accent))', - 'accent-foreground': 'hsl(var(--accent-on))', + /* + * shadcn's `accent` is its SUBTLE hover/selected surface — dropdown + * items, command rows, ghost-button hover. It is not the brand colour; + * that is `primary`, mapped below. + * + * Mapping `accent` to --accent (the brand) inverted this, so every + * hover state painted a full-strength brand block: in dark mode with + * the monochrome "pig" accent that is near-white, which made a selected + * command row glare. Aliased to the subtle pair instead, so shadcn + * primitives tint the way their authors intended while PIG's own brand + * fills use `primary`. + */ + accent: 'hsl(var(--accent-subtle))', + 'accent-foreground': 'hsl(var(--accent-fg))', + /** The brand itself, for PIG's own components that need a solid fill. */ + brand: 'hsl(var(--accent))', 'accent-fg': 'hsl(var(--accent-fg))', 'accent-on': 'hsl(var(--accent-on))', 'accent-subtle': 'hsl(var(--accent-subtle))',