feat(theme): R10 S2 — re-close the rem system (px-frozen labels/chrome -> rem)

The ~124 px-frozen text-[Npx] labels didn't track the Settings font-scale slider
while their rem-sized neighbours did. Add text-2xs (0.6875rem) / text-3xs
(0.625rem) font-size-ONLY tokens (no paired line-height -> matches the arbitrary
they replace, zero vertical-rhythm shift) and codemod every text-[Npx] to a rem
class (rare 8/9/12/13px -> rem arbitraries).

Also: --hdr-h 68px -> 4.25rem so header content clears the rem-sized pills at
scale 1.3 instead of sliding under; NavSidebar/SidePanel slot widths + their
icon/badge px sizes go rem so the rails keep pace with their (now-scaling)
labels; a w-24/h-[54px] thumb -> h-13.5 to preserve 16:9 at scale. Media
thumbnails, page-width caps and fixed container widths deliberately stay px.

Verified via getComputedStyle at scale 1.06/1.3: text-2xs 11.66->14.3px, header
clearance 72->88px, nav slot 246->302px — all scale proportionally.
This commit is contained in:
2026-08-09 03:18:04 +02:00
parent 5e1abaaf8c
commit ab873bbcaa
37 changed files with 144 additions and 142 deletions
+12 -12
View File
@@ -198,12 +198,12 @@ export default function NavSidebar({
}`}
>
<span className="relative shrink-0">
<Icon className="w-[18px] h-[18px]" />
<Icon className="w-4.5 h-4.5" />
{/* Collapsed rail: a numeric badge centred on a circle at the icon corner; the ring
matches the row background so it reads cleanly whether the row is active or not. */}
{show && slim && (
<span
className={`absolute -top-2 -right-2 min-w-[16px] h-4 px-1 rounded-full text-[10px] font-bold leading-none grid place-items-center ring-2 ${badgeColor} ${
className={`absolute -top-2 -right-2 min-w-4 h-4 px-1 rounded-full text-3xs font-bold leading-none grid place-items-center ring-2 ${badgeColor} ${
active ? "ring-accent" : "ring-bg"
}`}
>
@@ -214,7 +214,7 @@ export default function NavSidebar({
{!slim && <span className="truncate">{label}</span>}
{show && !slim && (
<span
className={`ml-auto min-w-[18px] h-[18px] px-1.5 rounded-full text-[11px] font-semibold leading-none inline-flex items-center justify-center tabular-nums ${badgeColor}`}
className={`ml-auto min-w-4.5 h-4.5 px-1.5 rounded-full text-2xs font-semibold leading-none inline-flex items-center justify-center tabular-nums ${badgeColor}`}
>
{badge > 99 ? "99+" : badge}
</span>
@@ -226,14 +226,14 @@ export default function NavSidebar({
return (
// Layout slot: reserves only the slim footprint when unpinned, so the expanded rail (below)
// overlays content instead of pushing it. Pinned reserves the full width (in-flow).
<div className={`relative shrink-0 transition-[width] ${pinned ? "w-[232px]" : "w-20"}`}>
<div className={`relative shrink-0 transition-[width] ${pinned ? "w-58" : "w-20"}`}>
<nav
// Peek handlers sit on the CARD, not the slot: the slot is wider than the card by its
// margin, and a hover zone out there would fire from the dead space next to the rail —
// leaving the side panel to the left would pop the rail open with nothing under the cursor.
{...peek.handlers}
className={`glass absolute top-0 bottom-0 left-0 z-rail rounded-2xl flex flex-col py-3 m-3 transition-[width] ${
slim ? "w-[56px] px-2" : "w-52 px-3"
slim ? "w-14 px-2" : "w-52 px-3"
}`}
aria-label={t("nav.primary")}
>
@@ -270,7 +270,7 @@ export default function NavSidebar({
<div className="my-2 mx-auto w-7 border-t-2 border-border" />
) : (
<div className="mt-4 mb-1 px-2.5 flex items-center gap-2">
<span className="text-[10px] font-semibold uppercase tracking-wider text-muted/70">
<span className="text-3xs font-semibold uppercase tracking-wider text-muted/70">
{t("nav.adminSection")}
</span>
<span className="flex-1 border-t border-border" />
@@ -314,7 +314,7 @@ export default function NavSidebar({
: "text-muted hover:text-fg hover:bg-card"
}`}
>
<Settings className="w-[18px] h-[18px] shrink-0" />
<Settings className="w-4.5 h-4.5 shrink-0" />
{!slim && <span className="truncate">{t("header.account.settings")}</span>}
</button>
@@ -329,7 +329,7 @@ export default function NavSidebar({
<AvatarImg
src={me.avatar_url}
fallback={name}
className="w-[22px] h-[22px] rounded-full text-[10px]"
className="w-5.5 h-5.5 rounded-full text-3xs"
/>
</span>
{!slim && (
@@ -356,7 +356,7 @@ export default function NavSidebar({
</div>
</div>
{me.role === "admin" && (
<div className="flex items-center gap-1.5 mt-2 text-[11px] font-medium text-accent">
<div className="flex items-center gap-1.5 mt-2 text-2xs font-medium text-accent">
<Shield className="w-3.5 h-3.5" />
{t("header.account.admin")}
</div>
@@ -373,13 +373,13 @@ export default function NavSidebar({
<AvatarImg
src={a.avatar_url}
fallback={a.display_name ?? a.email}
className="w-6 h-6 rounded-full text-[10px] shrink-0"
className="w-6 h-6 rounded-full text-3xs shrink-0"
/>
<span className="min-w-0 text-left">
<span className="block text-[13px] text-fg truncate">
<span className="block text-[0.8125rem] text-fg truncate">
{a.display_name ?? a.email.split("@")[0]}
</span>
<span className="block text-[11px] text-muted truncate">{a.email}</span>
<span className="block text-2xs text-muted truncate">{a.email}</span>
</span>
</button>
))}