Repository navigation
fix(admin): stop forcing every border to the default gray - #4118
Conversation
The admin stylesheet set `* { border-color: var(--color-kumo-line) }`
outside Tailwind's cascade layers. Unlayered rules beat layered ones
regardless of specificity, so every border color utility in the admin,
Kumo's included, drew the default gray instead. Moving the rule into
`@layer base` keeps the default for elements without a border color
class and lets the utilities win.
🦋 Changeset detectedLatest commit: 9219a17 The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
This PR fixes the issue correctly and with minimal scope. The unlayered * { border-color: var(--color-kumo-line) } rule in packages/admin/src/styles.css was indeed overriding every Tailwind border-* color utility regardless of specificity, because unlayered CSS always wins over layered CSS. Moving the rule into @layer base is the right, idiomatic Tailwind v4 fix: the universal selector keeps its zero specificity within the base layer, so utilities in higher layers (and with higher specificity) now win as intended. Elements without an explicit border color class still fall back to --color-kumo-line, preserving the original default behavior.
The regression test in ImageDropTargets.test.tsx is well targeted: it exercises the actual broken user-visible behavior (the Featured Image drop target should show a brand-colored border while a file is dragged over it) by asserting the computed borderTopColor, not by asserting class names. It would fail against main's stylesheet and passes with the fix. The changeset is user-facing, specific about observable effects, and follows .changeset/README.md conventions.
I checked the changed CSS, the drop-target component, the test setup, and the changeset. There are no logic bugs, API changes, security concerns, localization issues, RTL issues, or comment/AGENTS.md violations introduced here. The PR is clean.
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-test
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-loader
@emdash-cms/registry-moderation
@emdash-cms/registry-verification
upgrade-emdash
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 687e9c5 | Oct 12 2026, 12:05 PM |
…#4118) * fix(admin): stop forcing every border to the default gray The admin stylesheet set `* { border-color: var(--color-kumo-line) }` outside Tailwind's cascade layers. Unlayered rules beat layered ones regardless of specificity, so every border color utility in the admin, Kumo's included, drew the default gray instead. Moving the rule into `@layer base` keeps the default for elements without a border color class and lets the utilities win. * chore: simplify the border color changeset * chore: shorten the border color changeset
What does this PR do?
Fixes admin borders always being drawn in the default gray, even where a component asks for another color.
packages/admin/src/styles.cssset* { border-color: var(--color-kumo-line) }outside Tailwind's cascade layers. Unlayered CSS beats every layered rule regardless of specificity, so this rule overrode everyborder-*color class in the admin, including Kumo's own. I noticed it on the empty Featured Image drop target: while a file is dragged over it, the box getsborder-kumo-brand bg-kumo-tint, but only the tint showed and the border stayed gray.The rule now sits in
@layer base. Elements without a border color class still get--color-kumo-linein light and dark mode, and border color classes now win. Apart from the rule's position, the compiled stylesheet is unchanged.What changes on screen:
Bannernotices have no border and don't change.divide-kumo-line/50dividers now use their own grays.The Visual Regression screenshots still match their baselines, because the sidebar lines and gray shifts are below its per-pixel tolerance.
Type of change
Your connection to this change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain. Not applicable: no strings changed.AI assistance disclosure
Screenshots / test output
Before: while a file is dragged over the empty Featured Image box, the background tints but the dashed border stays gray.
After: the border turns blue.
Before: the media library's drop overlay has a gray dashed frame.
After: the frame is blue.
Before: the selected revision has a faint blue fill but a gray outline.
After: the selected revision has a blue outline.
Before: notices have a gray edge. Here, the error shown when users fail to load, and the invite link warning shown when no email provider is configured.
After: the edges are red and yellow.
Before: the expanded sidebar draws a line under each section label.
After: the expanded sidebar has no lines under the labels, as Kumo intends.
Every spot I compared, in light and dark mode
Tests:
packages/admin/tests/components/ImageDropTargets.test.tsx: the drop target's border is the brand color while a file is dragged over it. The test fails against main's stylesheet, where the border keeps the line color, and passes with the fix.--color-kumo-line; every difference comes from a border color class that now applies. The notice screenshots used mocked API responses to show the error and invite link states.