You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Graph Explorer's styling has accumulated legacy debt: a tailwind.config.ts that's redundant with Tailwind v4 CSS-native capabilities, ~18 legacy color token aliases used in 117 places across 64 files, orphaned dark mode fragments, shadcn compatibility aliases, and direct palette scale references that bypass the semantic token layer. There is no documented design system — contributors (human and agent) have no authoritative reference for which tokens to use, leading to further drift.
Solution
Eliminate the legacy styling debt, migrate all components to canonical semantic tokens, and produce a docs/agents/design.md that defines the design system. The result is a single CSS file (index.css) as the source of truth for all theme values, utilities, and color semantics — no JS config, no parallel vocabularies, no undocumented conventions.
User Stories
As a contributor modifying UI, I want a single authoritative design system document, so that I know which tokens are correct without reverse-engineering CSS.
As a contributor, I want all styling defined in CSS (no JS config file), so that the build is simpler and I don't need to check two places for theme values.
As a contributor, I want legacy color aliases deleted, so that I'm not confused by two names for the same value.
As a contributor, I want semantic tokens to be the strongly-preferred way to express color, so that future dark mode support doesn't require auditing individual components.
As a contributor using shadcn components, I want shadcn compatibility tokens inlined and removed, so that there's one vocabulary for everyone.
As a future implementer of dark mode, I want semantic tokens structured to support CSS light-dark() remapping, so that adding dark mode is a variable reassignment rather than a component-by-component rewrite.
As a contributor reviewing a PR, I want batch-by-token commits during migration, so that I can see how each legacy token maps to its semantic replacement and whether the semantic layer has gaps.
As a contributor, I want custom plugin utilities migrated to Tailwind v4 @utility syntax, so that no JS plugin code remains.
As a contributor, I want the gray palette documented as zinc-values-under-the-gray-name, so that I understand the one non-obvious remapping.
As a contributor, I want direct palette scale references in components to be exceptional and documented, not the norm, so that I default to semantic tokens.
As a contributor, I want orphaned dark mode fragments removed, so that incomplete code doesn't suggest dark mode is partially implemented.
As a contributor, I want docs/agents/tailwind.md merged into the new design doc, so that there's one styling reference, not two.
Implementation Decisions
Delete tailwind.config.ts entirely. All values move to CSS-native declarations:
Font families, font weights, z-index, keyframes, animations, logo-gradient, maxWidth.paragraph → @theme block in index.css
aria.invalid and data.open/closed extensions → dropped (native in Tailwind v4 as aria-invalid:, data-open:, data-closed:)
Semantic token names stay as-is. The existing token vocabulary (foreground, muted-foreground, primary, primary-foreground, etc.) is preserved. No renames. Documentation clarifies semantics for the naming system that's already in place.
Legacy alias section (lines 116–148 of index.css) is deleted after all 117 usages are migrated to canonical tokens. Migration is intent-based (choose the correct semantic token by the component's purpose) rather than mechanical (blind find-and-replace of the alias target).
shadcn compat tokens (destructive, popover, popover-foreground, accent, accent-foreground) inlined. The handful of shadcn-origin components (DropdownMenu, AlertDialog, Dialog) are rewritten to use canonical tokens (danger, background, foreground, primary-subtle, primary-foreground). Compat aliases deleted.
Orphaned dark mode removed. The @custom-variant dark declaration and 4 dark: usages across Field, DropdownMenu, Checkbox, CollapsibleSidebar are stripped. Dark mode is an intended future goal using light-dark() on semantic tokens.
Gray-is-zinc is documented. Tailwind's neutral scales (slate, zinc, neutral, stone) are removed; gray-* is redefined with zinc's oklch values. This is the single neutral palette. Documented, not renamed.
Direct palette scale references (brand-*, gray-* in components) are migrated to semantic tokens where a semantic intent exists. Palette scales remain available for genuine one-offs (e.g. logo-gradient) — preference, not prohibition.
Migration batched by token. Each legacy token gets its own commit (or small set of commits) to surface any poorly-defined semantic tokens that need refinement. Insights update the draft design doc.
design.md at docs/agents/design.md, referenced from AGENTS.md Conventions section. Absorbs tailwind.md content. Covers: token vocabulary and semantics, palette structure, gray-is-zinc, semantic-first preference with palette as legal one-off, dark mode future posture, Tailwind v4 conventions (prefer data attributes, responsive directives, v4 syntax).
Testing Decisions
This is a zero-behavior-change refactor — no new features, no logic changes. The test seam is the existing build pipeline:
pnpm checks must pass (types + lint + format) after every step
pnpm test must pass after every step
Tailwind's JIT compilation catches references to removed tokens as missing classes at build time — a broken reference becomes invisible (no error, no output), so visual verification via the running app is necessary after each major batch
No new automated tests needed. The codebase has no class-name snapshot tests and no visual regression test suite. The validation is that the app builds, renders, and looks the same. Each commit should be buildable and visually verifiable independently.
If any step reveals a semantic token gap (a usage that doesn't map cleanly to any existing token), the token is added to @theme, the draft design.md is updated, and a comment is left in the migration commit noting the addition.
Related Issues
Blocking Support dark mode #645 (Support dark mode — this work structures tokens for future light-dark() remapping)
Part of Use Tailwind & Radix #700 (Use Tailwind & Radix — this is the final cleanup step of that migration)
Out of Scope
Dark mode implementation (future, uses light-dark() on the token layer defined here)
Token renames or naming model changes (surface/on pattern, -fg suffix, etc. — deferred)
Custom spacing, radius, shadow, or typography token layers (Tailwind defaults are adequate)
Component library extraction or design system package
Storybook or visual regression testing infrastructure
Any user-facing behavior change
Further Notes
The vite.config.ts reference to tailwind.config.ts (as a dep for HMR) should be removed when the config file is deleted.
The @config "../tailwind.config.ts" directive in index.css should be removed when the config is deleted.
The 9 usages of custom plugin utilities (content-auto, content-hidden, content-visible, intrinsic-size-*) should be verified to still work after migrating from JS plugin to @utility — they're used for virtualized list performance.
Important
Internal only — this issue is maintained by the core team and is not accepting external contributions.
Problem Statement
Graph Explorer's styling has accumulated legacy debt: a
tailwind.config.tsthat's redundant with Tailwind v4 CSS-native capabilities, ~18 legacy color token aliases used in 117 places across 64 files, orphaned dark mode fragments, shadcn compatibility aliases, and direct palette scale references that bypass the semantic token layer. There is no documented design system — contributors (human and agent) have no authoritative reference for which tokens to use, leading to further drift.Solution
Eliminate the legacy styling debt, migrate all components to canonical semantic tokens, and produce a
docs/agents/design.mdthat defines the design system. The result is a single CSS file (index.css) as the source of truth for all theme values, utilities, and color semantics — no JS config, no parallel vocabularies, no undocumented conventions.User Stories
light-dark()remapping, so that adding dark mode is a variable reassignment rather than a component-by-component rewrite.@utilitysyntax, so that no JS plugin code remains.graypalette documented as zinc-values-under-the-gray-name, so that I understand the one non-obvious remapping.docs/agents/tailwind.mdmerged into the new design doc, so that there's one styling reference, not two.Implementation Decisions
Delete
tailwind.config.tsentirely. All values move to CSS-native declarations:maxWidth.paragraph→@themeblock inindex.cssaria.invalidanddata.open/closedextensions → dropped (native in Tailwind v4 asaria-invalid:,data-open:,data-closed:)content-auto,content-hidden,content-visible,intrinsic-size-*) →@utilityblocks inindex.cssSemantic token names stay as-is. The existing token vocabulary (
foreground,muted-foreground,primary,primary-foreground, etc.) is preserved. No renames. Documentation clarifies semantics for the naming system that's already in place.Legacy alias section (lines 116–148 of
index.css) is deleted after all 117 usages are migrated to canonical tokens. Migration is intent-based (choose the correct semantic token by the component's purpose) rather than mechanical (blind find-and-replace of the alias target).shadcn compat tokens (
destructive,popover,popover-foreground,accent,accent-foreground) inlined. The handful of shadcn-origin components (DropdownMenu, AlertDialog, Dialog) are rewritten to use canonical tokens (danger,background,foreground,primary-subtle,primary-foreground). Compat aliases deleted.Orphaned dark mode removed. The
@custom-variant darkdeclaration and 4dark:usages across Field, DropdownMenu, Checkbox, CollapsibleSidebar are stripped. Dark mode is an intended future goal usinglight-dark()on semantic tokens.Gray-is-zinc is documented. Tailwind's neutral scales (slate, zinc, neutral, stone) are removed;
gray-*is redefined with zinc's oklch values. This is the single neutral palette. Documented, not renamed.Direct palette scale references (
brand-*,gray-*in components) are migrated to semantic tokens where a semantic intent exists. Palette scales remain available for genuine one-offs (e.g.logo-gradient) — preference, not prohibition.Migration batched by token. Each legacy token gets its own commit (or small set of commits) to surface any poorly-defined semantic tokens that need refinement. Insights update the draft design doc.
Execution order:
design.mdtailwind.config.ts(migrate to CSS)design.md, deletetailwind.md, updateAGENTS.mddesign.mdatdocs/agents/design.md, referenced fromAGENTS.mdConventions section. Absorbstailwind.mdcontent. Covers: token vocabulary and semantics, palette structure, gray-is-zinc, semantic-first preference with palette as legal one-off, dark mode future posture, Tailwind v4 conventions (prefer data attributes, responsive directives, v4 syntax).Testing Decisions
This is a zero-behavior-change refactor — no new features, no logic changes. The test seam is the existing build pipeline:
pnpm checksmust pass (types + lint + format) after every steppnpm testmust pass after every stepNo new automated tests needed. The codebase has no class-name snapshot tests and no visual regression test suite. The validation is that the app builds, renders, and looks the same. Each commit should be buildable and visually verifiable independently.
If any step reveals a semantic token gap (a usage that doesn't map cleanly to any existing token), the token is added to
@theme, the draftdesign.mdis updated, and a comment is left in the migration commit noting the addition.Related Issues
light-dark()remapping)Out of Scope
light-dark()on the token layer defined here)-fgsuffix, etc. — deferred)Further Notes
vite.config.tsreference totailwind.config.ts(as a dep for HMR) should be removed when the config file is deleted.@config "../tailwind.config.ts"directive inindex.cssshould be removed when the config is deleted.content-auto,content-hidden,content-visible,intrinsic-size-*) should be verified to still work after migrating from JS plugin to@utility— they're used for virtualized list performance.Important
Internal only — this issue is maintained by the core team and is not accepting external contributions.