Background
Follow-up from a review comment on #76 (discussion) suggesting style={{ paddingInline: "var(--frame-gutter)" }} → className="px-[var(--frame-gutter)]" in Footer.tsx.
#4 only covered the theme color tokens (--color-ink, --color-paper, --color-whisper), which are wired into @theme inline in app/globals.css and auto-generate clean utilities (text-paper, bg-ink, …). The remaining inline-style CSS-var usages are all layout (--frame-*) and typography (--fs-*) tokens that currently live as plain :root custom properties — they don't generate any utilities, so they're stuck as either inline style={{}} or arbitrary-value classes.
Migrating just one site (e.g. only Footer.tsx) breaks consistency with its neighbours, which is why the suggestion was deferred. This issue tracks the broader pass.
In scope (34 sites)
paddingInline: "var(--frame-gutter)" (3)
maxWidth: "var(--frame-max)" (3)
Other --frame-* inline styles in Frame.tsx (2)
fontSize: "var(--fs-*)" (28)
| File |
Line |
Token |
app/blog/[slug]/page.tsx |
73 |
--fs-h2 |
app/blog/page.tsx |
48 |
--fs-h2 |
app/blog/page.tsx |
54 |
--fs-lead |
app/blog/page.tsx |
67 |
--fs-body |
app/blog/page.tsx |
89 |
--fs-h3 |
app/blog/page.tsx |
95 |
--fs-body |
components/site/Close.tsx |
43 |
--fs-body |
components/site/Close.tsx |
57 |
--fs-lead |
components/site/Close.tsx |
69 |
--fs-lead |
components/site/Close.tsx |
79 |
--fs-lead |
components/site/Comparison.tsx |
19 |
--fs-h2 |
components/site/Comparison.tsx |
29 |
--fs-body |
components/site/Comparison.tsx |
68 |
--fs-price |
components/site/Comparison.tsx |
88 |
--fs-price |
components/site/Faq.tsx |
16 |
--fs-h2 |
components/site/Footer.tsx |
14 |
--fs-micro |
components/site/Hero.tsx |
20 |
--fs-h1 |
components/site/Hero.tsx |
36 |
--fs-body |
components/site/Hero.tsx |
52 |
--fs-cta |
components/site/Hero.tsx |
64 |
--fs-cta |
components/site/Hero.tsx |
74 |
--fs-cta |
components/site/Method.tsx |
44 |
--fs-h3 |
components/ui/ComparisonRow.tsx |
17 |
--fs-body |
components/ui/FaqItem.tsx |
32 |
--fs-lead |
components/ui/FaqItem.tsx |
38 |
--fs-body |
components/ui/Figure.tsx |
7 |
--fs-body (+ letterSpacing) |
components/ui/MethodRow.tsx |
21 |
--fs-method-row (+ lineHeight) |
components/ui/MethodRow.tsx |
27 |
--fs-body |
Out of scope
Approach (open question)
Two viable directions; the migration looks very different depending on which we pick:
A. Promote tokens into @theme inline with Tailwind v4 namespace names so utilities auto-generate:
--text-h1, --text-body, … (Tailwind v4 --text-* namespace) → text-h1, text-body
--spacing-frame-gutter, --max-width-frame, … (similar namespaces) → px-frame-gutter, max-w-frame
- Pro: real utilities, no arbitrary-value classes, IDE autocomplete, doc-friendly.
- Con: renames the public CSS API; any external doc/MDX or
docs/ styling referencing var(--fs-h1) etc. needs an alias or a rename.
B. Arbitrary-value classes, keep the var names:
Recommendation: A is the more lasting fix; B is reasonable if the deadline pressure is real. Either way it's one bundled PR — partial migration causes the same inconsistency that motivated this issue.
Verification
Same triple as #4:
pnpm lint && pnpm exec tsc --noEmit && pnpm build
pnpm dev smoke check: hero/h2/h3 sizes unchanged, frame gutter and max width unchanged across §01–§05 and /blog, footer micro-meta size unchanged, no layout shift at viewport breakpoints (@md, @xl, @4xl).
- Optional: compare
out/_next/static/chunks/*.css size before/after — should not balloon.
Links
Background
Follow-up from a review comment on #76 (discussion) suggesting
style={{ paddingInline: "var(--frame-gutter)" }}→className="px-[var(--frame-gutter)]"inFooter.tsx.#4 only covered the theme color tokens (
--color-ink,--color-paper,--color-whisper), which are wired into@theme inlineinapp/globals.cssand auto-generate clean utilities (text-paper,bg-ink, …). The remaining inline-style CSS-var usages are all layout (--frame-*) and typography (--fs-*) tokens that currently live as plain:rootcustom properties — they don't generate any utilities, so they're stuck as either inlinestyle={{}}or arbitrary-value classes.Migrating just one site (e.g. only
Footer.tsx) breaks consistency with its neighbours, which is why the suggestion was deferred. This issue tracks the broader pass.In scope (34 sites)
paddingInline: "var(--frame-gutter)"(3)maxWidth: "var(--frame-max)"(3)Other
--frame-*inline styles inFrame.tsx(2)minHeight: "min(100svh, var(--frame-min-h-cap))"paddingBlock: "var(--frame-pad-y)"fontSize: "var(--fs-*)"(28)app/blog/[slug]/page.tsx--fs-h2app/blog/page.tsx--fs-h2app/blog/page.tsx--fs-leadapp/blog/page.tsx--fs-bodyapp/blog/page.tsx--fs-h3app/blog/page.tsx--fs-bodycomponents/site/Close.tsx--fs-bodycomponents/site/Close.tsx--fs-leadcomponents/site/Close.tsx--fs-leadcomponents/site/Close.tsx--fs-leadcomponents/site/Comparison.tsx--fs-h2components/site/Comparison.tsx--fs-bodycomponents/site/Comparison.tsx--fs-pricecomponents/site/Comparison.tsx--fs-pricecomponents/site/Faq.tsx--fs-h2components/site/Footer.tsx--fs-microcomponents/site/Hero.tsx--fs-h1components/site/Hero.tsx--fs-bodycomponents/site/Hero.tsx--fs-ctacomponents/site/Hero.tsx--fs-ctacomponents/site/Hero.tsx--fs-ctacomponents/site/Method.tsx--fs-h3components/ui/ComparisonRow.tsx--fs-bodycomponents/ui/FaqItem.tsx--fs-leadcomponents/ui/FaqItem.tsx--fs-bodycomponents/ui/Figure.tsx--fs-body(+letterSpacing)components/ui/MethodRow.tsx--fs-method-row(+lineHeight)components/ui/MethodRow.tsx--fs-bodyOut of scope
--reveal-delaywrites insidestyle={{}}— these set a CSS var that descendant CSS reads (animation orchestration), not a one-way styling lookup. Keep as inline style.scroll-mt-[var(--nav-h)]inFrame.tsx:23— already aclassName, not an inline style.Approach (open question)
Two viable directions; the migration looks very different depending on which we pick:
A. Promote tokens into
@theme inlinewith Tailwind v4 namespace names so utilities auto-generate:--text-h1,--text-body, … (Tailwind v4--text-*namespace) →text-h1,text-body--spacing-frame-gutter,--max-width-frame, … (similar namespaces) →px-frame-gutter,max-w-framedocs/styling referencingvar(--fs-h1)etc. needs an alias or a rename.B. Arbitrary-value classes, keep the var names:
text-[length:var(--fs-h1)],px-[var(--frame-gutter)],max-w-[var(--frame-max)].Recommendation: A is the more lasting fix; B is reasonable if the deadline pressure is real. Either way it's one bundled PR — partial migration causes the same inconsistency that motivated this issue.
Verification
Same triple as #4:
pnpm lint && pnpm exec tsc --noEmit && pnpm buildpnpm devsmoke check: hero/h2/h3 sizes unchanged, frame gutter and max width unchanged across §01–§05 and/blog, footer micro-meta size unchanged, no layout shift at viewport breakpoints (@md,@xl,@4xl).out/_next/static/chunks/*.csssize before/after — should not balloon.Links