vercel/platforms
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
15 files reviewed·July 25, 2026
Low
Design risk in this codebase.
More findings
Verdict
Solid structural bones undercut by small unfinished edges: failing contrast, drifted spacing, and straight apostrophes where polish should be. The biggest risk is that spacing values are duplicated raw across components, so one overlooked fix multiplies into two inconsistent places.
Files Rams reviewed
app/page.tsx
app/s/[subdomain]/page.tsx
app/admin/page.tsx
app/layout.tsx
app/admin/dashboard.tsx
app/globals.css
app/not-found.tsx
app/subdomain-form.tsx
components/ui/button.tsx
components/ui/card.tsx
components/ui/dialog.tsx
components/ui/emoji-picker.tsx
components/ui/popover.tsx
components/ui/input.tsx
components/ui/label.tsx
Spacing
app/subdomain-form.tsx:88
Arbitrary pixel values on the icon preview drift from the spacing scale
The icon preview container uses `min-w-[40px] min-h-[40px] pl-[14px]`, three arbitrary pixel values instead of the Tailwind spacing scale (e.g. w-10, h-10, pl-3.5/pl-4) used elsewhere in the form.
Why it matters
Every arbitrary value here is a number someone has to remember and re-derive by hand next time this component's padding or icon size needs to change, which is how spacing drift accumulates across a codebase.
Fix
Replace arbitrary pixel classes with the nearest Tailwind spacing scale tokens.
<div className="min-w-[40px] min-h-[40px] flex items-center pl-[14px] select-none"><div className="min-w-10 min-h-10 flex items-center pl-3.5 select-none">app/subdomain-form.tsx:108
Emoji picker dimensions duplicated as raw pixels across two components
`PopoverContent` sets `w-[256px]` and `EmojiPicker` sets `h-[300px] w-[256px]`, the same 256px width hardcoded twice in adjacent JSX instead of a single shared value.
Why it matters
Resizing the emoji picker requires editing two separate class strings in sync; miss one and the popover frame and its inner picker fall out of alignment, which is a maintenance cost for a purely cosmetic dimension.
Fix
Define the picker's width and height once and reference it from both elements instead of repeating the literal.
<PopoverContent
className="p-0 w-[256px]"
align="end"
sideOffset={5}
>
<EmojiPicker
className="h-[300px] w-[256px]"const PICKER_WIDTH = 'w-[256px]';
<PopoverContent
className={`p-0 ${PICKER_WIDTH}`}
align="end"
sideOffset={5}
>
<EmojiPicker
className={`h-[300px] ${PICKER_WIDTH}`}Typography
app/not-found.tsx:43
Straight apostrophes in "doesn't exist" and "hasn't been created" read as unpolished
The heading text "doesn't exist" (line 36) and the subtext "This subdomain hasn't been created yet." (line 43) both use straight apostrophes ('). This is the only user-facing copy on the entire error page, so its typographic finish carries more weight than usual.
Why it matters
A 404 page is often the first broken-link impression a visitor gets of the product; straight quotes next to a styled heading and gradient background read as an unfinished detail in an otherwise deliberate layout.
Fix
Replace straight apostrophes with curly (') apostrophes in user-facing copy.
This subdomain hasn't been created yet.This subdomain hasn’t been created yet.Get this score on every PR.
Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.
Install Rams freeColor
app/subdomain-form.tsx:48
Domain suffix text fails AA contrast against its gray background
The `.{rootDomain}` suffix span uses `text-gray-500` on `bg-gray-100`. That pairing computes to roughly 4.39:1, below the 4.5:1 threshold WCAG AA requires for normal-size text. It sits directly beside the subdomain input as part of the same visually merged control, so it reads as primary form content, not decoration.
Why it matters
Users with low vision or in bright ambient light have to work harder to confirm the domain suffix they're about to submit under, which is exactly the kind of detail people double-check before creating a subdomain.
Fix
Darken the suffix text to a shade that clears 4.5:1 against bg-gray-100 for normal-size text.
<span className="bg-gray-100 px-3 border border-l-0 border-input rounded-r-md text-gray-500 min-h-[36px] flex items-center">
.{rootDomain}
</span><span className="bg-gray-100 px-3 border border-l-0 border-input rounded-r-md text-gray-700 min-h-[36px] flex items-center">
.{rootDomain}
</span>UX
app/not-found.tsx:30
Full-height wrapper can clip content under mobile Safari's URL bar
The outer container on the not-found page uses `min-h-screen`, which resolves to 100vh, a value taller than the visible viewport on mobile Safari when the address bar is showing. Content centered with `justify-center` inside that box can end up partially hidden or requiring a scroll the user doesn't expect on first load.
Why it matters
On the exact device class most likely to hit a broken subdomain link from a shared URL, the recovery message and "Go to {rootDomain}" action can sit under browser chrome, adding friction right when the user needs the fastest way back.
Fix
Use the dynamic viewport unit so the container height tracks the actual visible area on mobile browsers.
<div className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-blue-50 to-white p-4"><div className="flex min-h-[100dvh] flex-col items-center justify-center bg-gradient-to-b from-blue-50 to-white p-4">Accessibility
Components
Motion
Craft
Working well
- The submit button's `text-white` on `bg-blue-600` (5.17:1) and its `hover:bg-blue-700` state (6.70:1) both clear AA comfortably, so the primary CTA stays readable through idle and hover states.
- Disabling the submit button until an icon is picked (`disabled={isPending || !icon}`) stops an invalid submission at the source instead of letting the user find out after a failed round trip.
- The empty state ("No subdomains have been created yet.") gives a designed, explicit message instead of leaving a blank grid, which keeps the page from reading as broken.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 59/100. This rescore on v0.0.3: 90/100.
This page is an automated design review of vercel/platforms’s UI code: 15 files read against 309 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.