build(deps): migrate Tailwind CSS v3.4 → v4

Root-fixes the opacity-modifier seed bug behind R10 S0: the theme colors were
bare `var(--x)` hex with no <alpha-value>, so `bg-accent/40`, `ring-accent/40`,
`border-border/60`, `text-muted/70`, … (~99 sites across 45 files) emitted no
CSS rule at all — latent no-ops. v4 implements the opacity modifier via
`color-mix`, so the modifier now works with the existing hex vars, no per-scheme
token duplication needed.

- `npx @tailwindcss/upgrade`: `@tailwind` directives → `@import "tailwindcss"`,
  JS config → CSS `@theme` (colors, --font-sans, the z-index tokens preserved),
  classname renames (rounded/shadow/blur scale, outline-none→outline-hidden,
  ring→ring-2) across 56 files; PostCSS plugin → @tailwindcss/postcss,
  autoprefixer removed (v4 prefixes for you).
- `@theme` → `@theme inline` (load-bearing): the color vars are redefined at
  runtime under html[data-scheme]/[data-theme]; inline resolves them at the use
  site so per-scheme opacity tints track the active scheme (the shadcn v4 pattern).
- Revert one codemod false-positive: it rewrote the English word "rounded" →
  "rounded-sm" inside a releaseNotes.ts prose sentence.

Gate green: tsc(app+node) / eslint 0-err / prettier / vitest 79 / knip.
Verified in-browser: bg-accent/15 now computes a scheme-tracking color at 0.15
alpha across all 6 schemes × 2 themes; the hand-rolled glass border/shadow/
radius/backdrop-filter render unchanged under v4.
This commit is contained in:
2026-08-08 00:50:05 +02:00
parent 1199bb0eaf
commit 70bda98868
60 changed files with 822 additions and 809 deletions
+5 -5
View File
@@ -327,7 +327,7 @@ export default function GlassTuner() {
onClick={() => setTab(t)}
className={`flex-1 rounded-lg px-2 py-1 text-xs capitalize ${
tab === t
? "bg-accent text-[color:var(--accent-fg)] font-semibold"
? "bg-accent text-(--accent-fg) font-semibold"
: "glass-card text-muted"
}`}
>
@@ -361,7 +361,7 @@ export default function GlassTuner() {
type="color"
value={swatches[p.k] || "#000000"}
onChange={(e) => setColor(p.k, e.target.value)}
className="w-8 h-6 rounded border border-border bg-transparent cursor-pointer"
className="w-8 h-6 rounded-sm border border-border bg-transparent cursor-pointer"
/>
<span className="flex-1">{p.label}</span>
<code className="text-[10px] text-muted">{swatches[p.k]}</code>
@@ -385,7 +385,7 @@ export default function GlassTuner() {
<div className="flex gap-1.5">
<button
onClick={copy}
className="flex-1 rounded-lg px-2 py-1.5 text-xs font-semibold bg-accent text-[color:var(--accent-fg)]"
className="flex-1 rounded-lg px-2 py-1.5 text-xs font-semibold bg-accent text-(--accent-fg)"
>
{copied ? "Copied ✓" : "Copy CSS"}
</button>
@@ -396,7 +396,7 @@ export default function GlassTuner() {
Reset
</button>
</div>
<pre className="text-[9.5px] leading-relaxed bg-[color:var(--bg)] border border-border/60 rounded-lg p-2 overflow-x-auto text-muted whitespace-pre">
<pre className="text-[9.5px] leading-relaxed bg-(--bg) border border-border/60 rounded-lg p-2 overflow-x-auto text-muted whitespace-pre">
{cssOut}
</pre>
</div>
@@ -419,7 +419,7 @@ function Ctl({ s, value, onChange }: { s: Slider; value: number; onChange: (v: n
step={s.step}
value={value}
onChange={(e) => onChange(Number(e.target.value))}
className="w-16 text-right text-[11px] tabular-nums rounded bg-card border border-border px-1.5 py-0.5 text-accent"
className="w-16 text-right text-[11px] tabular-nums rounded-sm bg-card border border-border px-1.5 py-0.5 text-accent"
/>
<input
type="range"