authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-24 10:49:05-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-24 10:49:05-07:00
logf26ee083fe41720207fb10616359500dcecc19d3
treec0668ed670d5c836eb9c1a00979e38a5d66a1435
parent315fcca10a826d8aa1cbdffc3ef5b5eb5a1e2f9d
signature Signed by PGP key B5690EEEBB952194

fix(web): appearance classes use theme tokens and scale values (#13397)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

109 files changed, 464 insertions(+), 433 deletions(-)

apps/web/src/browser/BrowserDeviceToolbar.tsx+1-1
...@@ -175,7 +175,7 @@ export function BrowserDeviceToolbar({...@@ -175,7 +175,7 @@ export function BrowserDeviceToolbar({
175 }}175 }}
176 >176 >
177 {width >= 560 ? (177 {width >= 560 ? (
178 <span className="mr-0.5 shrink-0 text-[11px] font-medium text-muted-foreground">178 <span className="mr-0.5 shrink-0 text-2xs font-medium text-muted-foreground">
179 Dimensions179 Dimensions
180 </span>180 </span>
181 ) : null}181 ) : null}
apps/web/src/browser/HostedBrowserWebview.tsx+1-1
...@@ -352,7 +352,7 @@ export function HostedBrowserWebview(props: {...@@ -352,7 +352,7 @@ export function HostedBrowserWebview(props: {
352 />352 />
353 {activeDrag ? (353 {activeDrag ? (
354 <div354 <div
355 className="pointer-events-none absolute z-40 -translate-x-1/2 rounded-md border border-border/80 bg-background/95 px-2 py-1 text-[11px] font-medium tabular-nums text-foreground shadow-md backdrop-blur-sm"355 className="pointer-events-none absolute z-40 -translate-x-1/2 rounded-md border border-border/80 bg-background/95 px-2 py-1 text-2xs font-medium tabular-nums text-foreground shadow-md backdrop-blur-sm"
356 style={{356 style={{
357 left: layout.viewportX + layout.viewportWidth / 2,357 left: layout.viewportX + layout.viewportWidth / 2,
358 top: layout.viewportY + 10,358 top: layout.viewportY + 10,
apps/web/src/components/AgentsPanel.tsx+12-12
...@@ -162,12 +162,12 @@ function AgentRow({ agent }: { agent: RuntimeSubagent }) {...@@ -162,12 +162,12 @@ function AgentRow({ agent }: { agent: RuntimeSubagent }) {
162 <span className="col-start-2 row-start-1 flex min-w-0 items-baseline gap-2">162 <span className="col-start-2 row-start-1 flex min-w-0 items-baseline gap-2">
163 <span className="min-w-0 truncate text-sm font-medium">{agent.title}</span>163 <span className="min-w-0 truncate text-sm font-medium">{agent.title}</span>
164 {role ? (164 {role ? (
165 <span className="max-w-28 shrink-0 truncate rounded-sm border border-border/60 px-1 font-mono text-[.65rem] text-muted-foreground">165 <span className="max-w-28 shrink-0 truncate rounded-sm border border-border/60 px-1 font-mono text-3xs text-muted-foreground">
166 {role}166 {role}
167 </span>167 </span>
168 ) : null}168 ) : null}
169 </span>169 </span>
170 <span className="col-start-3 row-start-1 min-w-14 text-right font-mono text-[.7rem] text-muted-foreground/80">170 <span className="col-start-3 row-start-1 min-w-14 text-right font-mono text-2xs text-muted-foreground/80">
171 <span className="inline-flex items-center gap-1">171 <span className="inline-flex items-center gap-1">
172 <AgentElapsed agent={agent} />172 <AgentElapsed agent={agent} />
173 {agent.status === "completed" ? (173 {agent.status === "completed" ? (
...@@ -183,7 +183,7 @@ function AgentRow({ agent }: { agent: RuntimeSubagent }) {...@@ -183,7 +183,7 @@ function AgentRow({ agent }: { agent: RuntimeSubagent }) {
183 >183 >
184 {activity ?? statusLabel}184 {activity ?? statusLabel}
185 </span>185 </span>
186 <span className="col-start-2 col-end-4 row-start-3 truncate font-mono text-[.7rem] tabular-nums text-muted-foreground/70">186 <span className="col-start-2 col-end-4 row-start-3 truncate font-mono text-2xs tabular-nums text-muted-foreground/70">
187 {metadata.join(" · ")}187 {metadata.join(" · ")}
188 </span>188 </span>
189 <span className="sr-only">{statusLabel}</span>189 <span className="sr-only">{statusLabel}</span>
...@@ -234,7 +234,7 @@ function PhaseRail({ group }: { group: AgentPanelWorkflowGroup }) {...@@ -234,7 +234,7 @@ function PhaseRail({ group }: { group: AgentPanelWorkflowGroup }) {
234 >234 >
235 <span235 <span
236 className={cn(236 className={cn(
237 "font-mono text-[.65rem]",237 "font-mono text-3xs",
238 phase.state === "running"238 phase.state === "running"
239 ? "text-info-foreground"239 ? "text-info-foreground"
240 : phase.state === "done"240 : phase.state === "done"
...@@ -247,7 +247,7 @@ function PhaseRail({ group }: { group: AgentPanelWorkflowGroup }) {...@@ -247,7 +247,7 @@ function PhaseRail({ group }: { group: AgentPanelWorkflowGroup }) {
247 </span>247 </span>
248 <span className="flex items-center gap-0.5">248 <span className="flex items-center gap-0.5">
249 {phase.members.length === 0 ? (249 {phase.members.length === 0 ? (
250 <span className="font-mono text-[.6rem] text-muted-foreground/50">–</span>250 <span className="font-mono text-3xs text-muted-foreground/50">–</span>
251 ) : (251 ) : (
252 phase.members.map((member) => <StatusDot key={member.id} status={member.status} />)252 phase.members.map((member) => <StatusDot key={member.id} status={member.status} />)
253 )}253 )}
...@@ -281,7 +281,7 @@ function WorkflowScriptView({...@@ -281,7 +281,7 @@ function WorkflowScriptView({
281 <div className="mx-1.5 mb-1 rounded-md border border-border/60 bg-background/60">281 <div className="mx-1.5 mb-1 rounded-md border border-border/60 bg-background/60">
282 <div className="flex items-center gap-2 border-b border-border/50 px-2 py-1">282 <div className="flex items-center gap-2 border-b border-border/50 px-2 py-1">
283 <Braces aria-hidden className="size-3 text-muted-foreground" />283 <Braces aria-hidden className="size-3 text-muted-foreground" />
284 <span className="truncate font-mono text-[.65rem] text-muted-foreground">284 <span className="truncate font-mono text-3xs text-muted-foreground">
285 {scriptPath.split("/").at(-1)}285 {scriptPath.split("/").at(-1)}
286 </span>286 </span>
287 <Button287 <Button
...@@ -296,7 +296,7 @@ function WorkflowScriptView({...@@ -296,7 +296,7 @@ function WorkflowScriptView({
296 </div>296 </div>
297 <div className="max-h-72 overflow-auto p-2">297 <div className="max-h-72 overflow-auto p-2">
298 {result._tag === "Success" ? (298 {result._tag === "Success" ? (
299 <pre className="whitespace-pre-wrap break-words font-mono text-[.7rem] leading-relaxed text-foreground/90">299 <pre className="whitespace-pre-wrap break-words font-mono text-2xs leading-relaxed text-foreground/90">
300 {result.value.contents}300 {result.value.contents}
301 {result.value.truncated ? "\n… (truncated)" : ""}301 {result.value.truncated ? "\n… (truncated)" : ""}
302 </pre>302 </pre>
...@@ -339,7 +339,7 @@ function PhaseSection({...@@ -339,7 +339,7 @@ function PhaseSection({
339 onClick={() => setOpen((value) => !value)}339 onClick={() => setOpen((value) => !value)}
340 aria-expanded={open}340 aria-expanded={open}
341 className={cn(341 className={cn(
342 "mt-2 flex w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-[.65rem] font-medium uppercase tracking-wider hover:bg-accent/40",342 "mt-2 flex w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-3xs font-medium uppercase tracking-wider hover:bg-accent/40",
343 phase.state === "done"343 phase.state === "done"
344 ? "text-success-foreground"344 ? "text-success-foreground"
345 : phase.state === "running"345 : phase.state === "running"
...@@ -399,7 +399,7 @@ function ExpandedWorkflowSection({...@@ -399,7 +399,7 @@ function ExpandedWorkflowSection({
399 const canShowScript = scriptPath !== undefined && environmentId !== null && threadId !== null;399 const canShowScript = scriptPath !== undefined && environmentId !== null && threadId !== null;
400 return (400 return (
401 <section className="rounded-lg border border-border/50 bg-card/30 p-1.5">401 <section className="rounded-lg border border-border/50 bg-card/30 p-1.5">
402 <div className="flex items-center gap-2 px-1.5 pt-0.5 text-[.65rem] font-medium uppercase tracking-wider text-muted-foreground">402 <div className="flex items-center gap-2 px-1.5 pt-0.5 text-3xs font-medium uppercase tracking-wider text-muted-foreground">
403 <StatusDot status={group.workflow.status} />403 <StatusDot status={group.workflow.status} />
404 <span className="min-w-0 truncate">404 <span className="min-w-0 truncate">
405 {group.workflow.workflowName ?? group.workflow.title}405 {group.workflow.workflowName ?? group.workflow.title}
...@@ -486,7 +486,7 @@ function CollapsedWorkflowSection({...@@ -486,7 +486,7 @@ function CollapsedWorkflowSection({
486 <span className="truncate text-sm">486 <span className="truncate text-sm">
487 {group.workflow.workflowName ?? group.workflow.title}487 {group.workflow.workflowName ?? group.workflow.title}
488 </span>488 </span>
489 <span className="ml-auto flex items-center gap-1.5 font-mono text-[.7rem] text-muted-foreground/80">489 <span className="ml-auto flex items-center gap-1.5 font-mono text-2xs text-muted-foreground/80">
490 {failed > 0 ? <span className="text-destructive-foreground">{failed} failed</span> : null}490 {failed > 0 ? <span className="text-destructive-foreground">{failed} failed</span> : null}
491 <span>{members.length} agents</span>491 <span>{members.length} agents</span>
492 <span className="tabular-nums">· {formatSubagentTokenCount(totalTokens)} tok</span>492 <span className="tabular-nums">· {formatSubagentTokenCount(totalTokens)} tok</span>
...@@ -557,7 +557,7 @@ export function AgentsPanel({...@@ -557,7 +557,7 @@ export function AgentsPanel({
557 ))}557 ))}
558 {model.directAgents.length > 0 ? (558 {model.directAgents.length > 0 ? (
559 <section>559 <section>
560 <div className="px-1.5 pt-1 text-[.65rem] font-medium uppercase tracking-wider text-muted-foreground">560 <div className="px-1.5 pt-1 text-3xs font-medium uppercase tracking-wider text-muted-foreground">
561 Direct spawns561 Direct spawns
562 </div>562 </div>
563 {model.directAgents.map((agent) => (563 {model.directAgents.map((agent) => (
...@@ -567,7 +567,7 @@ export function AgentsPanel({...@@ -567,7 +567,7 @@ export function AgentsPanel({
567 ) : null}567 ) : null}
568 </div>568 </div>
569 </ScrollArea>569 </ScrollArea>
570 <footer className="flex items-center justify-between border-t border-border/60 px-3 py-1.5 font-mono text-[.7rem] text-muted-foreground">570 <footer className="flex items-center justify-between border-t border-border/60 px-3 py-1.5 font-mono text-2xs text-muted-foreground">
571 <span className="flex items-center gap-2">571 <span className="flex items-center gap-2">
572 {model.runningCount + model.waitingCount > 0 ? (572 {model.runningCount + model.waitingCount > 0 ? (
573 <span className="text-info-foreground">573 <span className="text-info-foreground">
apps/web/src/components/BranchToolbar.tsx+2-2
...@@ -185,7 +185,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({...@@ -185,7 +185,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({
185 >185 >
186 <span186 <span
187 data-composer-label-motion187 data-composer-label-motion
188 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"188 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
189 >189 >
190 {autoEnvironmentLabel ??190 {autoEnvironmentLabel ??
191 (showEnvironmentIndicator ? (activeEnvironment?.label ?? "Run on") : workspaceLabel)}191 (showEnvironmentIndicator ? (activeEnvironment?.label ?? "Run on") : workspaceLabel)}
...@@ -197,7 +197,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({...@@ -197,7 +197,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({
197 if (isLocked) {197 if (isLocked) {
198 return (198 return (
199 <span199 <span
200 className="inline-flex h-7 min-w-0 max-w-[48%] flex-initial items-center justify-start gap-1 rounded-md border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6"200 className="inline-flex h-7 min-w-0 max-w-[48%] flex-initial items-center justify-start gap-1 rounded-md border border-transparent px-1.75 font-normal text-muted-foreground/70 text-xs sm:h-6"
201 data-composer-context-control201 data-composer-context-control
202 >202 >
203 {triggerContent}203 {triggerContent}
apps/web/src/components/BranchToolbarBranchSelector.tsx+2-2
...@@ -757,7 +757,7 @@ export function BranchToolbarBranchSelector({...@@ -757,7 +757,7 @@ export function BranchToolbarBranchSelector({
757 >757 >
758 <div className="flex w-full min-w-0 items-center justify-between gap-2">758 <div className="flex w-full min-w-0 items-center justify-between gap-2">
759 <MiddleTruncate value={itemValue} className="flex-1" />759 <MiddleTruncate value={itemValue} className="flex-1" />
760 {badge && <span className="shrink-0 text-[10px] text-muted-foreground/45">{badge}</span>}760 {badge && <span className="shrink-0 text-3xs text-muted-foreground/45">{badge}</span>}
761 </div>761 </div>
762 </ComboboxItem>762 </ComboboxItem>
763 );763 );
...@@ -819,7 +819,7 @@ export function BranchToolbarBranchSelector({...@@ -819,7 +819,7 @@ export function BranchToolbarBranchSelector({
819 >819 >
820 <span820 <span
821 data-composer-label-motion821 data-composer-label-motion
822 className="flex w-full max-w-[240px] transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"822 className="flex w-full max-w-[240px] transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
823 >823 >
824 <MiddleTruncate value={triggerLabel} />824 <MiddleTruncate value={triggerLabel} />
825 </span>825 </span>
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+3-3
...@@ -61,7 +61,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe...@@ -61,7 +61,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
61 <Tooltip>61 <Tooltip>
62 <TooltipTrigger62 <TooltipTrigger
63 render={<span />}63 render={<span />}
64 className="inline-flex h-7 min-w-0 items-center gap-1 border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6"64 className="inline-flex h-7 min-w-0 items-center gap-1 border border-transparent px-1.75 font-normal text-muted-foreground/70 text-xs sm:h-6"
65 data-composer-context-control65 data-composer-context-control
66 >66 >
67 {forceNewWorktree ? (67 {forceNewWorktree ? (
...@@ -77,7 +77,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe...@@ -77,7 +77,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
77 >77 >
78 <span78 <span
79 data-composer-label-motion79 data-composer-label-motion
80 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"80 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
81 >81 >
82 {forceNewWorktree82 {forceNewWorktree
83 ? resolveEnvModeLabel("worktree")83 ? resolveEnvModeLabel("worktree")
...@@ -133,7 +133,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe...@@ -133,7 +133,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
133 >133 >
134 <span134 <span
135 data-composer-label-motion135 data-composer-label-motion
136 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"136 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
137 >137 >
138 <SelectValue />138 <SelectValue />
139 </span>139 </span>
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+3-3
...@@ -63,7 +63,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir...@@ -63,7 +63,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
63 <Tooltip>63 <Tooltip>
64 <TooltipTrigger64 <TooltipTrigger
65 render={<span />}65 render={<span />}
66 className="inline-flex h-7 min-w-0 max-w-full items-center gap-1 border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6"66 className="inline-flex h-7 min-w-0 max-w-full items-center gap-1 border border-transparent px-1.75 font-normal text-muted-foreground/70 text-xs sm:h-6"
67 data-composer-context-control67 data-composer-context-control
68 >68 >
69 <EnvironmentMachineIcon69 <EnvironmentMachineIcon
...@@ -76,7 +76,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir...@@ -76,7 +76,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
76 >76 >
77 <span77 <span
78 data-composer-label-motion78 data-composer-label-motion
79 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"79 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
80 >80 >
81 {activeEnvironment?.label ?? "Run on"}81 {activeEnvironment?.label ?? "Run on"}
82 </span>82 </span>
...@@ -123,7 +123,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir...@@ -123,7 +123,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
123 >123 >
124 <span124 <span
125 data-composer-label-motion125 data-composer-label-motion
126 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"126 className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none"
127 >127 >
128 <SelectValue />128 <SelectValue />
129 </span>129 </span>
apps/web/src/components/ChatMarkdown.tsx+3-3
...@@ -974,12 +974,12 @@ function MarkdownCodeBlock({...@@ -974,12 +974,12 @@ function MarkdownCodeBlock({
974974
975 return (975 return (
976 <div976 <div
977 className="chat-markdown-codeblock my-[0.65rem] overflow-hidden rounded-[var(--radius)] border border-border/70 bg-secondary leading-snug dark:border-transparent dark:bg-input/32"977 className="chat-markdown-codeblock my-[0.65rem] overflow-hidden rounded-lg border border-border/70 bg-secondary leading-snug dark:border-transparent dark:bg-input/32"
978 data-language={language}978 data-language={language}
979 data-wrap={wrapped ? "true" : "false"}979 data-wrap={wrapped ? "true" : "false"}
980 >980 >
981 <div className="chat-markdown-codeblock-header flex items-center justify-between gap-2 pt-1.5 pr-1.5 pb-0 pl-3 select-none">981 <div className="chat-markdown-codeblock-header flex items-center justify-between gap-2 pt-1.5 pr-1.5 pb-0 pl-3 select-none">
982 <span className="inline-flex min-w-0 items-center gap-[0.4rem] [font-family:var(--font-mono,ui-monospace,SFMono-Regular,monospace)] [font-size:0.6875rem]">982 <span className="inline-flex min-w-0 items-center gap-1.5 font-mono text-2xs">
983 <MarkdownCodeBlockTitleContent983 <MarkdownCodeBlockTitleContent
984 fenceTitle={fenceTitle}984 fenceTitle={fenceTitle}
985 language={language}985 language={language}
...@@ -2201,7 +2201,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({...@@ -2201,7 +2201,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({
2201 <TooltipPopup side="top" variant="code">2201 <TooltipPopup side="top" variant="code">
2202 {/* The full path: the chip already shows the shortened form, and a link2202 {/* The full path: the chip already shows the shortened form, and a link
2203 to the workspace root collapses to a bare label that repeats it. */}2203 to the workspace root collapses to a bare label that repeats it. */}
2204 <div className="overflow-x-auto whitespace-nowrap [scrollbar-color:color-mix(in_srgb,var(--contrast-border)_78%,transparent)_transparent] [scrollbar-width:thin] [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-[color-mix(in_srgb,var(--contrast-border)_78%,transparent)] [&::-webkit-scrollbar-track]:bg-transparent">2204 <div className="overflow-x-auto whitespace-nowrap scrollbar-thumb-border/78 scrollbar-track-transparent [scrollbar-width:thin] [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-border/78 [&::-webkit-scrollbar-track]:bg-transparent">
2205 {targetPath}2205 {targetPath}
2206 </div>2206 </div>
2207 </TooltipPopup>2207 </TooltipPopup>
apps/web/src/components/ChatView.tsx+3-3
...@@ -1220,7 +1220,7 @@ const PersistentThreadTerminalDrawer = memo(function PersistentThreadTerminalDra...@@ -1220,7 +1220,7 @@ const PersistentThreadTerminalDrawer = memo(function PersistentThreadTerminalDra
1220 "grid shrink-0 overflow-clip",1220 "grid shrink-0 overflow-clip",
1221 active ? (visible ? "grid-rows-[1fr]" : "grid-rows-[0fr]") : "hidden",1221 active ? (visible ? "grid-rows-[1fr]" : "grid-rows-[0fr]") : "hidden",
1222 active &&1222 active &&
1223 "[[data-panel-animations=true]_&]:transition-[grid-template-rows] [[data-panel-animations=true]_&]:[transition-duration:var(--panel-animation-duration)] [[data-panel-animations=true]_&]:ease-out",1223 "[[data-panel-animations=true]_&]:transition-[grid-template-rows] [[data-panel-animations=true]_&]:duration-(--panel-animation-duration) [[data-panel-animations=true]_&]:ease-out",
1224 active && visible && "[[data-panel-animations=true]_&]:starting:grid-rows-[0fr]!",1224 active && visible && "[[data-panel-animations=true]_&]:starting:grid-rows-[0fr]!",
1225 )}1225 )}
1226 >1226 >
...@@ -9588,7 +9588,7 @@ export default function ChatView(props: ChatViewProps) {...@@ -9588,7 +9588,7 @@ export default function ChatView(props: ChatViewProps) {
9588 className={cn(9588 className={cn(
9589 "flex shrink-0",9589 "flex shrink-0",
9590 panelAnimationsActive &&9590 panelAnimationsActive &&
9591 "motion-safe:transition-opacity motion-safe:[transition-duration:var(--panel-animation-duration)] motion-safe:ease-out",9591 "motion-safe:transition-opacity motion-safe:duration-(--panel-animation-duration) motion-safe:ease-out",
9592 rightPanelOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0",9592 rightPanelOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0",
9593 )}9593 )}
9594 inert={!rightPanelOpen}9594 inert={!rightPanelOpen}
...@@ -10015,7 +10015,7 @@ export default function ChatView(props: ChatViewProps) {...@@ -10015,7 +10015,7 @@ export default function ChatView(props: ChatViewProps) {
10015 >10015 >
10016 <div10016 <div
10017 ref={attachDraftHeroTransitionGroupRef}10017 ref={attachDraftHeroTransitionGroupRef}
10018 className="w-full ps-[calc(env(safe-area-inset-left)+0.75rem)] pe-[calc(env(safe-area-inset-right)+0.75rem)] sm:ps-[calc(env(safe-area-inset-left)+1.25rem)] sm:pe-[calc(env(safe-area-inset-right)+1.25rem)]"10018 className="w-full ps-(--workspace-gutter-start) pe-(--workspace-gutter-end)"
10019 >10019 >
10020 <div10020 <div
10021 data-chat-composer-stack="true"10021 data-chat-composer-stack="true"
apps/web/src/components/ComposerPromptEditorTiptap.tsx+2-2
...@@ -190,7 +190,7 @@ function resolvedThemeFromDocument(): "light" | "dark" {...@@ -190,7 +190,7 @@ function resolvedThemeFromDocument(): "light" | "dark" {
190 * paints the editor's node selection over it.190 * paints the editor's node selection over it.
191 */191 */
192const CHIP_NODE_SELECTION_CLASS_NAME =192const CHIP_NODE_SELECTION_CLASS_NAME =
193 "relative inline-flex select-none items-center align-middle leading-none data-[composer-chip-selected]:after:pointer-events-none data-[composer-chip-selected]:after:absolute data-[composer-chip-selected]:after:inset-0 data-[composer-chip-selected]:after:rounded-[6px] data-[composer-chip-selected]:after:bg-[Highlight] data-[composer-chip-selected]:after:opacity-30 data-[composer-chip-selected]:after:content-['']";193 "relative inline-flex select-none items-center align-middle leading-none data-[composer-chip-selected]:after:pointer-events-none data-[composer-chip-selected]:after:absolute data-[composer-chip-selected]:after:inset-0 data-[composer-chip-selected]:after:rounded-sm data-[composer-chip-selected]:after:bg-[Highlight] data-[composer-chip-selected]:after:opacity-30 data-[composer-chip-selected]:after:content-['']";
194194
195const ComposerMentionExtension = Node.create({195const ComposerMentionExtension = Node.create({
196 name: "composer-mention",196 name: "composer-mention",
...@@ -1242,7 +1242,7 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {...@@ -1242,7 +1242,7 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {
1242 <ComposerCitationCommentContext value={citationCommentActions}>1242 <ComposerCitationCommentContext value={citationCommentActions}>
1243 <div1243 <div
1244 className={cn(1244 className={cn(
1245 "relative flow-root [font-family:var(--font-composer,var(--font-sans))] [font-size:var(--font-size-prompt,0.875rem)] [@media(max-width:39.999rem)_and_(pointer:coarse)]:[font-size:max(var(--font-size-prompt,1rem),16px)]",1245 "relative flow-root font-(family-name:--font-composer,var(--font-sans)) text-(length:--font-size-prompt,var(--text-sm)) max-sm:pointer-coarse:text-(length:--font-size-prompt-touch)",
1246 containerClassName,1246 containerClassName,
1247 )}1247 )}
1248 >1248 >
apps/web/src/components/ContextChip.tsx+3-3
...@@ -23,7 +23,7 @@ import { cn } from "~/lib/utils";...@@ -23,7 +23,7 @@ import { cn } from "~/lib/utils";
23 * span with tabIndex for a tooltip) gets the focus outline.23 * span with tabIndex for a tooltip) gets the focus outline.
24 */24 */
25const contextChipVariants = cva(25const contextChipVariants = cva(
26 "inline-flex h-[1.41em] max-w-full items-center gap-[0.33em] rounded-[0.5em] border px-[0.5em] align-middle font-medium text-[0.86em] leading-none [&_svg]:block [&_svg]:size-[1.17em] [&_svg]:shrink-0 [&_svg]:self-center [button&,a&,[data-popup-open]&]:cursor-pointer [button&,a&]:transition-colors [button&,a&]:motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--contrast-foreground)] disabled:cursor-default",26 "inline-flex h-[1.41em] max-w-full items-center gap-[0.33em] rounded-[0.5em] border px-[0.5em] align-middle font-medium text-[0.86em] leading-none [&_svg]:block [&_svg]:size-[1.17em] [&_svg]:shrink-0 [&_svg]:self-center [button&,a&,[data-popup-open]&]:cursor-pointer [button&,a&]:transition-colors [button&,a&]:motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-foreground disabled:cursor-default",
27 {27 {
28 defaultVariants: { kind: "neutral" },28 defaultVariants: { kind: "neutral" },
29 variants: {29 variants: {
...@@ -71,7 +71,7 @@ const contextChipVariants = cva(...@@ -71,7 +71,7 @@ const contextChipVariants = cva(
71 "citation",71 "citation",
72 ],72 ],
73 className:73 className:
74 "border-[color-mix(in_oklab,var(--context-chip-accent)_34%,var(--contrast-border))] bg-[color-mix(in_oklab,var(--context-chip-accent)_11%,transparent)] text-[color-mix(in_oklab,var(--context-chip-accent)_22%,var(--contrast-foreground))] [button:enabled&,a&]:hover:border-[color-mix(in_oklab,var(--context-chip-accent)_48%,var(--contrast-border))] [button:enabled&,a&]:hover:bg-[color-mix(in_oklab,var(--context-chip-accent)_17%,transparent)]",74 "[--context-chip-border:color-mix(in_oklab,var(--context-chip-accent)_34%,var(--contrast-border))] [--context-chip-border-hover:color-mix(in_oklab,var(--context-chip-accent)_48%,var(--contrast-border))] [--context-chip-foreground:color-mix(in_oklab,var(--context-chip-accent)_22%,var(--contrast-foreground))] border-(--context-chip-border) bg-(--context-chip-accent)/11 text-(--context-chip-foreground) [button:enabled&,a&]:hover:border-(--context-chip-border-hover) [button:enabled&,a&]:hover:bg-(--context-chip-accent)/17",
75 },75 },
76 // State colors win over any kind.76 // State colors win over any kind.
77 { state: "unresolved", className: "text-foreground" },77 { state: "unresolved", className: "text-foreground" },
...@@ -115,7 +115,7 @@ function ContextChipLabel({ className, ...props }: React.ComponentProps<"span">)...@@ -115,7 +115,7 @@ function ContextChipLabel({ className, ...props }: React.ComponentProps<"span">)
115function ContextChipAction({ className, render, ...props }: useRender.ComponentProps<"button">) {115function ContextChipAction({ className, render, ...props }: useRender.ComponentProps<"button">) {
116 const defaultProps = {116 const defaultProps = {
117 className: cn(117 className: cn(
118 "ml-[0.17em] inline-flex size-[1.17em] shrink-0 cursor-pointer items-center justify-center rounded-sm text-current transition-colors hover:bg-[color-mix(in_oklab,var(--context-chip-accent,var(--color-foreground))_17%,transparent)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring motion-reduce:transition-none [&_svg]:size-[0.85em]",118 "ml-[0.17em] inline-flex size-[1.17em] shrink-0 cursor-pointer items-center justify-center rounded-sm text-current transition-colors hover:bg-(--context-chip-accent,var(--color-foreground))/17 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring motion-reduce:transition-none [&_svg]:size-[0.85em]",
119 className,119 className,
120 ),120 ),
121 "data-slot": "context-chip-action",121 "data-slot": "context-chip-action",
apps/web/src/components/DiffPanel.tsx+6-6
...@@ -765,7 +765,7 @@ export default function DiffPanel({...@@ -765,7 +765,7 @@ export default function DiffPanel({
765 value={baseRefQuery}765 value={baseRefQuery}
766 onChange={(event) => setBaseRefQuery(event.target.value)}766 onChange={(event) => setBaseRefQuery(event.target.value)}
767 />767 />
768 <div className="grid shrink-0 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2 border-b border-border/70 ps-3 pe-6.5 pt-2 pb-1.5 font-medium text-[10px] text-muted-foreground uppercase tracking-wide">768 <div className="grid shrink-0 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2 border-b border-border/70 ps-3 pe-6.5 pt-2 pb-1.5 font-medium text-3xs text-muted-foreground uppercase tracking-wide">
769 <span aria-hidden="true" />769 <span aria-hidden="true" />
770 <div className="grid min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center">770 <div className="grid min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center">
771 <span>Branch</span>771 <span>Branch</span>
...@@ -841,7 +841,7 @@ export default function DiffPanel({...@@ -841,7 +841,7 @@ export default function DiffPanel({
841 <DiffStatLabel841 <DiffStatLabel
842 additions={diffLineStat.additions}842 additions={diffLineStat.additions}
843 deletions={diffLineStat.deletions}843 deletions={diffLineStat.deletions}
844 className="mr-1 text-[11px]"844 className="mr-1 text-2xs"
845 layout="inline"845 layout="inline"
846 />846 />
847 ) : null}847 ) : null}
...@@ -992,14 +992,14 @@ export default function DiffPanel({...@@ -992,14 +992,14 @@ export default function DiffPanel({
992 <>992 <>
993 <div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden bg-background">993 <div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden bg-background">
994 {isSelectedPatchTruncated && !lazySource && (994 {isSelectedPatchTruncated && !lazySource && (
995 <p className="shrink-0 border-b border-border/70 bg-muted/40 px-3 py-1.5 text-[11px] text-muted-foreground">995 <p className="shrink-0 border-b border-border/70 bg-muted/40 px-3 py-1.5 text-2xs text-muted-foreground">
996 This preview exceeds the size limit. Changes shown are incomplete.996 This preview exceeds the size limit. Changes shown are incomplete.
997 {selectedGitSource?.files ? " Totals include all changes." : ""}997 {selectedGitSource?.files ? " Totals include all changes." : ""}
998 </p>998 </p>
999 )}999 )}
1000 {selectedPatchError && !renderablePatch && (1000 {selectedPatchError && !renderablePatch && (
1001 <div className="px-3">1001 <div className="px-3">
1002 <p className="mb-2 text-[11px] text-error/80">{selectedPatchError}</p>1002 <p className="mb-2 text-2xs text-error/80">{selectedPatchError}</p>
1003 </div>1003 </div>
1004 )}1004 )}
1005 {!renderablePatch && !lazySource ? (1005 {!renderablePatch && !lazySource ? (
...@@ -1181,12 +1181,12 @@ export default function DiffPanel({...@@ -1181,12 +1181,12 @@ export default function DiffPanel({
1181 ) : (1181 ) : (
1182 <div className="min-h-0 flex-1 overflow-auto p-2">1182 <div className="min-h-0 flex-1 overflow-auto p-2">
1183 <div className="space-y-2">1183 <div className="space-y-2">
1184 <p className="text-[11px] text-muted-foreground/75">1184 <p className="text-2xs text-muted-foreground/75">
1185 {renderablePatch?.kind === "raw" ? renderablePatch.reason : null}1185 {renderablePatch?.kind === "raw" ? renderablePatch.reason : null}
1186 </p>1186 </p>
1187 <pre1187 <pre
1188 className={cn(1188 className={cn(
1189 "max-h-[72vh] rounded-md border border-border/70 bg-background/70 p-3 font-mono text-[11px] leading-relaxed text-muted-foreground/90",1189 "max-h-[72vh] rounded-md border border-border/70 bg-background/70 p-3 font-mono text-2xs leading-relaxed text-muted-foreground/90",
1190 wordWrap1190 wordWrap
1191 ? "overflow-auto whitespace-pre-wrap wrap-break-word"1191 ? "overflow-auto whitespace-pre-wrap wrap-break-word"
1192 : "overflow-auto",1192 : "overflow-auto",
apps/web/src/components/DiffPanelShell.tsx+1-1
...@@ -13,7 +13,7 @@ function getDiffPanelHeaderRowClassName(mode: DiffPanelMode) {...@@ -13,7 +13,7 @@ function getDiffPanelHeaderRowClassName(mode: DiffPanelMode) {
13 "flex items-center justify-between gap-2",13 "flex items-center justify-between gap-2",
14 mode === "embedded" ? "px-2" : "px-4",14 mode === "embedded" ? "px-2" : "px-4",
15 shouldUseDragRegion15 shouldUseDragRegion
16 ? "drag-region h-[var(--workspace-topbar-height)] border-b border-border wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]"16 ? "drag-region h-[var(--workspace-topbar-height)] border-b border-border wco:h-[env(titlebar-area-height)] wco:pr-(--workspace-native-controls-inset)"
17 : "flex h-10 min-h-10 shrink-0 items-center border-b border-border/60 bg-background in-data-[preview-panel-mode=inline]:mb-3 in-data-[preview-panel-mode=inline]:h-7 in-data-[preview-panel-mode=inline]:min-h-7 in-data-[preview-panel-mode=inline]:border-b-transparent",17 : "flex h-10 min-h-10 shrink-0 items-center border-b border-border/60 bg-background in-data-[preview-panel-mode=inline]:mb-3 in-data-[preview-panel-mode=inline]:h-7 in-data-[preview-panel-mode=inline]:min-h-7 in-data-[preview-panel-mode=inline]:border-b-transparent",
18 );18 );
19}19}
apps/web/src/components/LegacySidebar.tsx+5-5
...@@ -234,7 +234,7 @@ const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> =...@@ -234,7 +234,7 @@ const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> =
234 separate: "Keep separate",234 separate: "Keep separate",
235};235};
236const SIDEBAR_ICON_ACTION_BUTTON_CLASS =236const SIDEBAR_ICON_ACTION_BUTTON_CLASS =
237 "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-[calc(--spacing(1)-1px)] text-icon-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring";237 "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-0.75 text-icon-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring";
238238
239function SidebarThreadDetailPrewarmer({ threadRef }: { readonly threadRef: ScopedThreadRef }) {239function SidebarThreadDetailPrewarmer({ threadRef }: { readonly threadRef: ScopedThreadRef }) {
240 useEnvironmentThread(threadRef.environmentId, threadRef.threadId);240 useEnvironmentThread(threadRef.environmentId, threadRef.threadId);
...@@ -850,7 +850,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP...@@ -850,7 +850,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
850 data-thread-selection-safe850 data-thread-selection-safe
851 data-testid={`thread-archive-confirm-${thread.id}`}851 data-testid={`thread-archive-confirm-${thread.id}`}
852 aria-label={`Confirm archive ${thread.title}`}852 aria-label={`Confirm archive ${thread.title}`}
853 className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-md bg-destructive/12 px-2 text-[10px] font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-destructive/40"853 className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-md bg-destructive/12 px-2 text-3xs font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-destructive/40"
854 onPointerDown={stopPropagationOnPointerDown}854 onPointerDown={stopPropagationOnPointerDown}
855 onClick={handleConfirmArchiveClick}855 onClick={handleConfirmArchiveClick}
856 >856 >
...@@ -920,7 +920,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP...@@ -920,7 +920,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
920 render={920 render={
921 <span921 <span
922 aria-label={jumpLabel}922 aria-label={jumpLabel}
923 className="inline-flex h-5 items-center rounded-full border border-border/80 bg-background/90 px-1.5 font-mono text-[10px] font-medium tracking-tight text-foreground shadow-sm"923 className="inline-flex h-5 items-center rounded-full border border-border/80 bg-background/90 px-1.5 font-mono text-3xs font-medium tracking-tight text-foreground shadow-sm"
924 />924 />
925 }925 }
926 >926 >
...@@ -930,7 +930,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP...@@ -930,7 +930,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
930 </Tooltip>930 </Tooltip>
931 ) : (931 ) : (
932 <span932 <span
933 className={`text-[10px] tabular-nums ${933 className={`text-3xs tabular-nums ${
934 isHighlighted ? "text-foreground" : "text-secondary-label"934 isHighlighted ? "text-foreground" : "text-secondary-label"
935 }`}935 }`}
936 >936 >
...@@ -2410,7 +2410,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec...@@ -2410,7 +2410,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
2410 {project.displayName}2410 {project.displayName}
2411 </span>2411 </span>
2412 {project.groupedProjectCount > 1 ? (2412 {project.groupedProjectCount > 1 ? (
2413 <span className="shrink-0 text-secondary-label text-[10px]">2413 <span className="shrink-0 text-secondary-label text-3xs">
2414 {project.groupedProjectCount} projects2414 {project.groupedProjectCount} projects
2415 </span>2415 </span>
2416 ) : null}2416 ) : null}
apps/web/src/components/ProjectFavicon.tsx+2-2
...@@ -19,7 +19,7 @@ const DynamicIcon = lazy(() =>...@@ -19,7 +19,7 @@ const DynamicIcon = lazy(() =>
19);19);
2020
21function DynamicProjectIconFallback() {21function DynamicProjectIconFallback() {
22 return <FolderCodeIcon className="size-full text-[inherit]" />;22 return <FolderCodeIcon className="size-full text-inherit" />;
23}23}
2424
25// The slice of a project that decides its icon. Every surface must pass the25// The slice of a project that decides its icon. Every surface must pass the
...@@ -176,7 +176,7 @@ function ProjectFaviconImage({...@@ -176,7 +176,7 @@ function ProjectFaviconImage({
176 <img176 <img
177 src={displayedSrc}177 src={displayedSrc}
178 alt=""178 alt=""
179 className={cn("size-3.5 shrink-0 rounded-[37.5%] object-contain", className)}179 className={cn("size-3.5 shrink-0 rounded-[25%] object-contain", className)}
180 onError={() => handleLoadError(displayedSrc)}180 onError={() => handleLoadError(displayedSrc)}
181 />181 />
182 ) : null}182 ) : null}
apps/web/src/components/PullRequestContextDetails.tsx+1-1
...@@ -15,7 +15,7 @@ export function PullRequestContextDetails({ metadata }: { metadata: PullRequestC...@@ -15,7 +15,7 @@ export function PullRequestContextDetails({ metadata }: { metadata: PullRequestC
15 <span className={state.toneClassName}>{state.label}</span>15 <span className={state.toneClassName}>{state.label}</span>
16 </div>16 </div>
17 <div className="wrap-break-word text-foreground">{metadata.title}</div>17 <div className="wrap-break-word text-foreground">{metadata.title}</div>
18 <div className="flex min-w-0 items-center gap-1 text-secondary-label text-[10px]">18 <div className="flex min-w-0 items-center gap-1 text-secondary-label text-3xs">
19 <code className="truncate">{metadata.headBranch}</code>19 <code className="truncate">{metadata.headBranch}</code>
20 <ArrowRightIcon className="size-3 shrink-0" aria-hidden="true" />20 <ArrowRightIcon className="size-3 shrink-0" aria-hidden="true" />
21 <code className="truncate">{metadata.baseBranch}</code>21 <code className="truncate">{metadata.baseBranch}</code>
apps/web/src/components/RightPanelTabs.tsx+11-10
...@@ -488,7 +488,7 @@ function RightPanelEmptyState(props: {...@@ -488,7 +488,7 @@ function RightPanelEmptyState(props: {
488 {action.badgeCount > 0 ? (488 {action.badgeCount > 0 ? (
489 <span489 <span
490 aria-hidden490 aria-hidden
491 className="absolute -top-1.5 -right-2 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-[9px] font-semibold tabular-nums text-white"491 className="absolute -top-1.5 -right-2 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-3xs font-semibold tabular-nums text-white"
492 >492 >
493 {action.badgeCount}493 {action.badgeCount}
494 </span>494 </span>
...@@ -505,13 +505,13 @@ function RightPanelEmptyState(props: {...@@ -505,13 +505,13 @@ function RightPanelEmptyState(props: {
505 aria-label="Open a surface"505 aria-label="Open a surface"
506 data-surface-launcher-keys={availableActions.map((action) => action.shortcut).join("")}506 data-surface-launcher-keys={availableActions.map((action) => action.shortcut).join("")}
507 className={cn(507 className={cn(
508 "flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-6 pt-6 outline-none",508 "flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-6 outline-none",
509 // The panel topbar sits above this container; matching bottom padding509 // The panel topbar sits above this container; matching bottom padding
510 // keeps the list centered against the full panel, not the leftover.510 // keeps the list centered against the full panel, not the leftover.
511 "pb-[calc(var(--workspace-topbar-height)+--spacing(6))]",511 "pb-(--workspace-topbar-height)",
512 )}512 )}
513 >513 >
514 <div className="w-full max-w-xs">514 <div className="w-full max-w-xs py-6">
515 <h3 className="mb-3 text-center font-medium text-foreground text-sm">Open a surface</h3>515 <h3 className="mb-3 text-center font-medium text-foreground text-sm">Open a surface</h3>
516 <div className="flex flex-col gap-0.5">516 <div className="flex flex-col gap-0.5">
517 {actions.map((action) =>517 {actions.map((action) =>
...@@ -534,7 +534,7 @@ function RightPanelEmptyState(props: {...@@ -534,7 +534,7 @@ function RightPanelEmptyState(props: {
534 type="button"534 type="button"
535 onClick={action.onClick}535 onClick={action.onClick}
536 className={cn(536 className={cn(
537 "flex h-8 w-full cursor-pointer items-center gap-2.5 rounded-[var(--control-radius)] px-2.5 text-left text-sm transition-colors group-hover:bg-accent/60",537 "flex h-8 w-full cursor-pointer items-center gap-2.5 rounded-(--control-radius) px-2.5 text-left text-sm transition-colors group-hover:bg-accent/60",
538 isHighlighted(action) && "bg-accent/60",538 isHighlighted(action) && "bg-accent/60",
539 )}539 )}
540 >540 >
...@@ -589,7 +589,7 @@ function RightPanelEmptyState(props: {...@@ -589,7 +589,7 @@ function RightPanelEmptyState(props: {
589 <div589 <div
590 tabIndex={0}590 tabIndex={0}
591 aria-disabled="true"591 aria-disabled="true"
592 className="flex h-8 w-full cursor-default items-center gap-2.5 rounded-[var(--control-radius)] px-2.5 text-left text-sm opacity-50"592 className="flex h-8 w-full cursor-default items-center gap-2.5 rounded-(--control-radius) px-2.5 text-left text-sm opacity-50"
593 >593 >
594 {actionIcon(action, "size-4")}594 {actionIcon(action, "size-4")}
595 <span className="min-w-0 flex-1 truncate">{action.label}</span>595 <span className="min-w-0 flex-1 truncate">{action.label}</span>
...@@ -1114,10 +1114,7 @@ export function RightPanelTabs(props: RightPanelTabsProps) {...@@ -1114,10 +1114,7 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
1114 // controls a few pixels higher and the cluster jumps on open.1114 // controls a few pixels higher and the cluster jumps on open.
1115 props.mode === "inline" && !props.layoutControls ? "pr-28" : "pr-3",1115 props.mode === "inline" && !props.layoutControls ? "pr-28" : "pr-3",
1116 ownsDesktopTitleBar && "drag-region",1116 ownsDesktopTitleBar && "drag-region",
1117 ownsDesktopTitleBar &&1117 ownsDesktopTitleBar && "wco:pr-(--workspace-native-controls-inset)",
1118 (props.layoutControls
1119 ? "wco:pr-[var(--workspace-native-controls-inset)]"
1120 : "wco:pr-[calc(var(--workspace-native-controls-inset)+6rem)]"),
1121 props.mode === "inline" && props.maximized && COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,1118 props.mode === "inline" && props.maximized && COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,
1122 )}1119 )}
1123 data-right-panel-tabbar1120 data-right-panel-tabbar
...@@ -1395,6 +1392,10 @@ export function RightPanelTabs(props: RightPanelTabsProps) {...@@ -1395,6 +1392,10 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
1395 </div>1392 </div>
1396 ) : null}1393 ) : null}
1397 {props.layoutControls}1394 {props.layoutControls}
1395 {ownsDesktopTitleBar && !props.layoutControls ? (
1396 // Keeps the tabs clear of the window controls when the layout toggles live elsewhere.
1397 <span aria-hidden className="hidden w-24 shrink-0 wco:block" />
1398 ) : null}
1398 {ownsDesktopTitleBar ? (1399 {ownsDesktopTitleBar ? (
1399 <span1400 <span
1400 aria-hidden1401 aria-hidden
apps/web/src/components/Sidebar.tsx+8-8
...@@ -283,7 +283,7 @@ function JumpHintBadge(props: { label: string }) {...@@ -283,7 +283,7 @@ function JumpHintBadge(props: { label: string }) {
283 return (283 return (
284 <span284 <span
285 aria-hidden285 aria-hidden
286 className="pointer-events-none absolute right-1.5 top-1/2 z-10 inline-flex h-5 -translate-y-1/2 items-center rounded-full border border-border/80 bg-background/95 px-1.5 font-mono text-[10px] font-medium tracking-tight text-foreground shadow-sm"286 className="pointer-events-none absolute right-1.5 top-1/2 z-10 inline-flex h-5 -translate-y-1/2 items-center rounded-full border border-border/80 bg-background/95 px-1.5 font-mono text-3xs font-medium tracking-tight text-foreground shadow-sm"
287 >287 >
288 {props.label}288 {props.label}
289 </span>289 </span>
...@@ -760,7 +760,7 @@ const SidebarDraftRow = memo(function SidebarDraftRow(props: {...@@ -760,7 +760,7 @@ const SidebarDraftRow = memo(function SidebarDraftRow(props: {
760 onClick={handleActivate}760 onClick={handleActivate}
761 onKeyDown={handleKeyDown}761 onKeyDown={handleKeyDown}
762 >762 >
763 <div className="relative z-10 h-[4.875rem] px-[var(--sidebar-row-content-inset)] py-[var(--sidebar-content-inset)]">763 <div className="relative z-10 h-[4.875rem] px-(--sidebar-row-content-inset) py-(--sidebar-content-inset)">
764 <div className="flex h-5 min-w-0 items-center gap-1.5">764 <div className="flex h-5 min-w-0 items-center gap-1.5">
765 <SquarePenIcon aria-hidden className={draftPenClassName} />765 <SquarePenIcon aria-hidden className={draftPenClassName} />
766 {props.project ? (766 {props.project ? (
...@@ -1408,7 +1408,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1408,7 +1408,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1408 // keeps the hover color applied, so both the tint and the solid sidebar1408 // keeps the hover color applied, so both the tint and the solid sidebar
1409 // color are stacked as background images.1409 // color are stacked as background images.
1410 props.sortable?.isDragging &&1410 props.sortable?.isDragging &&
1411 "bg-[linear-gradient(var(--sidebar-row-active),var(--sidebar-row-active)),linear-gradient(var(--sidebar),var(--sidebar))] text-sidebar-foreground opacity-100 shadow-lg",1411 "bg-sidebar bg-linear-to-b from-sidebar-row-active to-sidebar-row-active text-sidebar-foreground opacity-100 shadow-lg",
1412 );1412 );
1413 // dnd-kit props for the row root. Same bag on both variants: every row in1413 // dnd-kit props for the row root. Same bag on both variants: every row in
1414 // the list translates around the gap as the drag passes it.1414 // the list translates around the gap as the drag passes it.
...@@ -1433,7 +1433,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1433,7 +1433,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1433 sortable?.isDragging && props.dropVerb !== null ? (1433 sortable?.isDragging && props.dropVerb !== null ? (
1434 <span1434 <span
1435 role="status"1435 role="status"
1436 className="pointer-events-none ml-auto inline-flex h-5 shrink-0 items-center gap-1 rounded-sm border border-primary/40 bg-primary/10 px-1.5 text-[11px] font-medium text-primary"1436 className="pointer-events-none ml-auto inline-flex h-5 shrink-0 items-center gap-1 rounded-sm border border-primary/40 bg-primary/10 px-1.5 text-2xs font-medium text-primary"
1437 >1437 >
1438 {dropVerbBadge[props.dropVerb]}1438 {dropVerbBadge[props.dropVerb]}
1439 </span>1439 </span>
...@@ -1478,7 +1478,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1478,7 +1478,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1478 ? "text-muted-foreground"1478 ? "text-muted-foreground"
1479 : "text-secondary-label/70",1479 : "text-secondary-label/70",
1480 ),1480 ),
1481 isRegeneratingTitle && "opacity-[0.55]",1481 isRegeneratingTitle && "opacity-55",
1482 )}1482 )}
1483 >1483 >
1484 {thread.title}1484 {thread.title}
...@@ -1745,7 +1745,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1745,7 +1745,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1745 />1745 />
1746 }1746 }
1747 >1747 >
1748 <div className="relative z-10 h-[4.875rem] px-[var(--sidebar-row-content-inset)] py-[var(--sidebar-content-inset)]">1748 <div className="relative z-10 h-[4.875rem] px-(--sidebar-row-content-inset) py-(--sidebar-content-inset)">
1749 <div className="flex h-5 min-w-0 items-center gap-1.5">1749 <div className="flex h-5 min-w-0 items-center gap-1.5">
1750 {draftIndicator}1750 {draftIndicator}
1751 {props.project ? (1751 {props.project ? (
...@@ -1956,7 +1956,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1956,7 +1956,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1956 showBadge={showInstanceBadge}1956 showBadge={showInstanceBadge}
1957 // Glyph dims, badge stays saturated; offset matches the composer trigger.1957 // Glyph dims, badge stays saturated; offset matches the composer trigger.
1958 iconClassName="size-3.5 opacity-60"1958 iconClassName="size-3.5 opacity-60"
1959 badgeClassName="right-[-0.1875rem] bottom-[-0.1875rem] h-3 min-w-3 px-0.5 text-[7px]"1959 badgeClassName="right-[-0.1875rem] bottom-[-0.1875rem] h-3 min-w-3 px-0.5 text-3xs"
1960 />1960 />
1961 </span>1961 </span>
1962 ) : null}1962 ) : null}
...@@ -4912,7 +4912,7 @@ export default function Sidebar() {...@@ -4912,7 +4912,7 @@ export default function Sidebar() {
4912 <button4912 <button
4913 type="button"4913 type="button"
4914 onClick={openAddProjectCommandPalette}4914 onClick={openAddProjectCommandPalette}
4915 className="inline-flex cursor-pointer items-center gap-1.5 rounded-md border border-sidebar-border px-2.5 py-1 text-[11px] font-medium text-sidebar-muted-foreground transition-colors hover:bg-sidebar-row-hover hover:text-sidebar-foreground"4915 className="inline-flex cursor-pointer items-center gap-1.5 rounded-md border border-sidebar-border px-2.5 py-1 text-2xs font-medium text-sidebar-muted-foreground transition-colors hover:bg-sidebar-row-hover hover:text-sidebar-foreground"
4916 >4916 >
4917 <PlusIcon className="-mx-0.5 size-3" />4917 <PlusIcon className="-mx-0.5 size-3" />
4918 Add project4918 Add project
apps/web/src/components/SlowRpcRequestToastCoordinator.tsx+1-1
...@@ -22,7 +22,7 @@ function SlowRequestDetails({ requests }: { requests: ReadonlyArray<SlowRpcAckRe...@@ -22,7 +22,7 @@ function SlowRequestDetails({ requests }: { requests: ReadonlyArray<SlowRpcAckRe
22 key={request.requestId}22 key={request.requestId}
23 >23 >
24 <div className="wrap-break-word font-medium text-foreground">{request.tag}</div>24 <div className="wrap-break-word font-medium text-foreground">{request.tag}</div>
25 <div className="mt-0.5 text-[10px] opacity-75">25 <div className="mt-0.5 text-3xs opacity-75">
26 Started {new Date(request.startedAt).toLocaleTimeString()}26 Started {new Date(request.startedAt).toLocaleTimeString()}
27 </div>27 </div>
28 </li>28 </li>
apps/web/src/components/ThreadStatusIndicators.tsx+2-2
...@@ -328,7 +328,7 @@ export function ThreadPullRequestsMiniList({...@@ -328,7 +328,7 @@ export function ThreadPullRequestsMiniList({
328 {snapshot?.title ?? line.link.repository}328 {snapshot?.title ?? line.link.repository}
329 </span>329 </span>
330 {line.stack ? (330 {line.stack ? (
331 <span className="ml-auto shrink-0 pl-1 text-[10px]">331 <span className="ml-auto shrink-0 pl-1 text-3xs">
332 {line.stack.kind === "native" ? "stack" : "chain"} · {line.stack.size}332 {line.stack.kind === "native" ? "stack" : "chain"} · {line.stack.size}
333 </span>333 </span>
334 ) : null}334 ) : null}
...@@ -463,7 +463,7 @@ export function ThreadStatusLabel({...@@ -463,7 +463,7 @@ export function ThreadStatusLabel({
463 render={463 render={
464 <span464 <span
465 aria-label={status.label}465 aria-label={status.label}
466 className={`inline-flex items-center gap-1 text-[10px] ${status.colorClass}`}466 className={`inline-flex items-center gap-1 text-3xs ${status.colorClass}`}
467 />467 />
468 }468 }
469 >469 >
apps/web/src/components/ThreadTerminalDrawer.tsx+4-4
...@@ -981,7 +981,7 @@ export function TerminalViewport({...@@ -981,7 +981,7 @@ export function TerminalViewport({
981 <div981 <div
982 ref={containerRef}982 ref={containerRef}
983 tabIndex={-1}983 tabIndex={-1}
984 className="relative h-full w-full overflow-hidden bg-[var(--terminal-background)]"984 className="relative h-full w-full overflow-hidden bg-(--terminal-background)"
985 />985 />
986 );986 );
987}987}
...@@ -1490,7 +1490,7 @@ export default function ThreadTerminalDrawer({...@@ -1490,7 +1490,7 @@ export default function ThreadTerminalDrawer({
1490 <div className="min-h-0 w-full flex-1">1490 <div className="min-h-0 w-full flex-1">
1491 <div1491 <div
1492 className={cn(1492 className={cn(
1493 "flex h-full min-h-0 bg-[var(--terminal-background)]",1493 "flex h-full min-h-0 bg-(--terminal-background)",
1494 hasTerminalSidebar && "gap-1.5",1494 hasTerminalSidebar && "gap-1.5",
1495 )}1495 )}
1496 >1496 >
...@@ -1653,7 +1653,7 @@ export default function ThreadTerminalDrawer({...@@ -1653,7 +1653,7 @@ export default function ThreadTerminalDrawer({
1653 {showGroupHeaders && (1653 {showGroupHeaders && (
1654 <button1654 <button
1655 type="button"1655 type="button"
1656 className={`flex h-[22px] w-full cursor-pointer items-center gap-1 rounded px-1.5 text-[11px] ${1656 className={`flex h-[22px] w-full cursor-pointer items-center gap-1 rounded px-1.5 text-2xs ${
1657 isGroupActive1657 isGroupActive
1658 ? "bg-accent/50 text-foreground"1658 ? "bg-accent/50 text-foreground"
1659 : "text-muted-foreground hover:bg-accent/40 hover:text-foreground"1659 : "text-muted-foreground hover:bg-accent/40 hover:text-foreground"
...@@ -1662,7 +1662,7 @@ export default function ThreadTerminalDrawer({...@@ -1662,7 +1662,7 @@ export default function ThreadTerminalDrawer({
1662 >1662 >
1663 <GroupIcon className="size-3 shrink-0" />1663 <GroupIcon className="size-3 shrink-0" />
1664 <span className="min-w-0 flex-1 truncate text-left">{groupLabel}</span>1664 <span className="min-w-0 flex-1 truncate text-left">{groupLabel}</span>
1665 <span className="text-muted-foreground/70 text-[10px] tabular-nums">1665 <span className="text-muted-foreground/70 text-3xs tabular-nums">
1666 {terminalCount}1666 {terminalCount}
1667 </span>1667 </span>
1668 </button>1668 </button>
apps/web/src/components/WorkspaceBreadcrumb.tsx+1-1
...@@ -33,7 +33,7 @@ export function WorkspaceBreadcrumbText({ children, className, ...props }: Compo...@@ -33,7 +33,7 @@ export function WorkspaceBreadcrumbText({ children, className, ...props }: Compo
33 // Center the capital letters with adjacent icons, not the font's leading.33 // Center the capital letters with adjacent icons, not the font's leading.
34 // Padding preserves accents and descenders when a label is truncated.34 // Padding preserves accents and descenders when a label is truncated.
35 className={cn(35 className={cn(
36 "block min-w-0 truncate [text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:py-[0.5em]",36 "block min-w-0 truncate [text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:py-1.5",
37 className,37 className,
38 )}38 )}
39 {...props}39 {...props}
apps/web/src/components/WorkspacePageHeader.tsx+2-2
...@@ -16,9 +16,9 @@ export function WorkspacePageHeader({...@@ -16,9 +16,9 @@ export function WorkspacePageHeader({
16 return (16 return (
17 <header17 <header
18 className={cn(18 className={cn(
19 "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center gap-3 pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] [[data-panel-animations=true]_&]:motion-safe:transition-[padding-left,padding-right] [[data-panel-animations=true]_&]:motion-safe:[transition-duration:var(--panel-animation-duration)] [[data-panel-animations=true]_&]:motion-safe:ease-out sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)]",19 "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center gap-3 pl-(--workspace-gutter-start) pr-(--workspace-gutter-end) [[data-panel-animations=true]_&]:motion-safe:transition-[padding-left,padding-right] [[data-panel-animations=true]_&]:motion-safe:duration-(--panel-animation-duration) [[data-panel-animations=true]_&]:motion-safe:ease-out",
20 electron && "drag-region",20 electron && "drag-region",
21 reserveNativeControls && "wco:pr-[var(--workspace-native-controls-inset)]",21 reserveNativeControls && "wco:pr-(--workspace-native-controls-inset)",
22 COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,22 COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS,
23 className,23 className,
24 )}24 )}
apps/web/src/components/auth/AuthSurfaceShell.tsx+1-1
...@@ -27,7 +27,7 @@ export function AuthSurfaceShell({ children }: { readonly children: ReactNode })...@@ -27,7 +27,7 @@ export function AuthSurfaceShell({ children }: { readonly children: ReactNode })
27 )}27 )}
28 <div className="absolute inset-0 bg-[linear-gradient(to_bottom,transparent_20%,rgba(7,18,55,0.46)_100%)]" />28 <div className="absolute inset-0 bg-[linear-gradient(to_bottom,transparent_20%,rgba(7,18,55,0.46)_100%)]" />
29 <div className="relative h-full p-5 sm:p-6">29 <div className="relative h-full p-5 sm:p-6">
30 <p className="text-[10px] font-semibold tracking-[0.2em] text-white/80 uppercase">30 <p className="text-3xs font-semibold tracking-widest text-white/80 uppercase">
31 {APP_DISPLAY_NAME}31 {APP_DISPLAY_NAME}
32 </p>32 </p>
33 </div>33 </div>
apps/web/src/components/chat/AssistantCitationChip.tsx+2-2
...@@ -110,7 +110,7 @@ export function AssistantCitationChip({...@@ -110,7 +110,7 @@ export function AssistantCitationChip({
110 const composerSourceLink = (110 const composerSourceLink = (
111 <Link111 <Link
112 {...sourceLinkProps}112 {...sourceLinkProps}
113 className="inline-flex h-full min-w-0 items-center gap-[0.33em] rounded-sm text-inherit no-underline focus-visible:outline-2 focus-visible:outline-[var(--contrast-foreground)]"113 className="inline-flex h-full min-w-0 items-center gap-[0.33em] rounded-sm text-inherit no-underline focus-visible:outline-2 focus-visible:outline-foreground"
114 aria-label={`View cited assistant text: ${label}`}114 aria-label={`View cited assistant text: ${label}`}
115 >115 >
116 <QuoteIcon aria-hidden="true" />116 <QuoteIcon aria-hidden="true" />
...@@ -120,7 +120,7 @@ export function AssistantCitationChip({...@@ -120,7 +120,7 @@ export function AssistantCitationChip({
120 const chatSourceLink = (120 const chatSourceLink = (
121 <Link121 <Link
122 {...sourceLinkProps}122 {...sourceLinkProps}
123 className="inline-flex h-full min-w-0 items-center gap-[0.33em] rounded-sm text-inherit no-underline hover:bg-[color-mix(in_oklab,var(--context-chip-accent)_17%,transparent)] focus-visible:outline-2 focus-visible:outline-[var(--contrast-foreground)]"123 className="inline-flex h-full min-w-0 items-center gap-[0.33em] rounded-sm text-inherit no-underline hover:bg-(--context-chip-accent)/17 focus-visible:outline-2 focus-visible:outline-foreground"
124 aria-label={`View cited assistant text: ${label}`}124 aria-label={`View cited assistant text: ${label}`}
125 >125 >
126 <QuoteIcon aria-hidden="true" />126 <QuoteIcon aria-hidden="true" />
apps/web/src/components/chat/ChangedFilesTree.tsx+4-4
...@@ -54,7 +54,7 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: {...@@ -54,7 +54,7 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: {
54 >54 >
55 <div55 <div
56 data-changed-files-header=""56 data-changed-files-header=""
57 className="sticky top-2 z-10 flex items-center justify-between gap-2 rounded-t-lg bg-secondary px-3 py-2 dark:bg-[color-mix(in_srgb,var(--input)_20%,var(--background))]"57 className="sticky top-2 z-10 flex items-center justify-between gap-2 rounded-t-lg bg-secondary px-3 py-2 dark:bg-background dark:bg-linear-to-b dark:from-input/20 dark:to-input/20"
58 >58 >
59 <div className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-xs font-medium text-foreground">59 <div className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-xs font-medium text-foreground">
60 <span>60 <span>
...@@ -206,11 +206,11 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {...@@ -206,11 +206,11 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {
206 ) : (206 ) : (
207 <FolderClosedIcon className="size-3.5 shrink-0 text-muted-foreground/75" />207 <FolderClosedIcon className="size-3.5 shrink-0 text-muted-foreground/75" />
208 )}208 )}
209 <span className="truncate font-mono text-[11px] text-muted-foreground/90 group-hover:text-foreground/90">209 <span className="truncate font-mono text-2xs text-muted-foreground/90 group-hover:text-foreground/90">
210 {node.name}210 {node.name}
211 </span>211 </span>
212 {hasNonZeroStat(node.stat) && (212 {hasNonZeroStat(node.stat) && (
213 <span className="ml-auto shrink-0 font-mono text-[10px] tabular-nums">213 <span className="ml-auto shrink-0 font-mono text-3xs tabular-nums">
214 <DiffStatLabel additions={node.stat.additions} deletions={node.stat.deletions} />214 <DiffStatLabel additions={node.stat.additions} deletions={node.stat.deletions} />
215 </span>215 </span>
216 )}216 )}
...@@ -251,7 +251,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {...@@ -251,7 +251,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {
251 <MiddleTruncate value={node.name} />251 <MiddleTruncate value={node.name} />
252 </span>252 </span>
253 {node.stat && (253 {node.stat && (
254 <span className="ml-auto shrink-0 font-mono text-[10px] tabular-nums">254 <span className="ml-auto shrink-0 font-mono text-3xs tabular-nums">
255 <DiffStatLabel additions={node.stat.additions} deletions={node.stat.deletions} />255 <DiffStatLabel additions={node.stat.additions} deletions={node.stat.deletions} />
256 </span>256 </span>
257 )}257 )}
apps/web/src/components/chat/ChatComposer.tsx+8-8
...@@ -381,7 +381,7 @@ function SnapShotAttachmentFrame({...@@ -381,7 +381,7 @@ function SnapShotAttachmentFrame({
381 className={cn(381 className={cn(
382 animateArrival &&382 animateArrival &&
383 !animationId &&383 !animationId &&
384 "origin-center transition-[opacity,scale] duration-300 ease-[cubic-bezier(.2,.8,.2,1)] starting:scale-95 starting:opacity-0 motion-reduce:transition-none motion-reduce:starting:scale-100 motion-reduce:starting:opacity-100",384 "origin-center transition-[opacity,scale] duration-300 ease-drawer starting:scale-95 starting:opacity-0 motion-reduce:transition-none motion-reduce:starting:scale-100 motion-reduce:starting:opacity-100",
385 className,385 className,
386 )}386 )}
387 {...props}387 {...props}
...@@ -6365,7 +6365,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6365,7 +6365,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6365 data-chat-composer-surface="true"6365 data-chat-composer-surface="true"
6366 data-chat-composer-mobile-collapsed={isComposerCollapsedMobile ? "true" : "false"}6366 data-chat-composer-mobile-collapsed={isComposerCollapsedMobile ? "true" : "false"}
6367 className={cn(6367 className={cn(
6368 "rounded-[20px] transition-[background-color] duration-200",6368 "rounded-3xl transition-[background-color] duration-200",
6369 isDragOverComposer ? "bg-accent/45 ring-1 ring-primary/70" : null,6369 isDragOverComposer ? "bg-accent/45 ring-1 ring-primary/70" : null,
6370 projectSelectionRequired ? "opacity-75" : null,6370 projectSelectionRequired ? "opacity-75" : null,
6371 composerProviderState.composerSurfaceClassName,6371 composerProviderState.composerSurfaceClassName,
...@@ -6377,7 +6377,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6377,7 +6377,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6377 type="button"6377 type="button"
6378 data-chat-composer-transition-prompt="true"6378 data-chat-composer-transition-prompt="true"
6379 className={cn(6379 className={cn(
6380 "min-w-0 flex-1 truncate bg-transparent p-0 text-left text-[14px] focus:outline-none",6380 "min-w-0 flex-1 truncate bg-transparent p-0 text-left text-sm focus:outline-none",
6381 (activePendingProgress ? activePendingProgress.customAnswer : prompt.trim())6381 (activePendingProgress ? activePendingProgress.customAnswer : prompt.trim())
6382 ? "text-foreground"6382 ? "text-foreground"
6383 : "text-placeholder",6383 : "text-placeholder",
...@@ -6477,7 +6477,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6477,7 +6477,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6477 "mb-3 flex max-w-full gap-2",6477 "mb-3 flex max-w-full gap-2",
6478 pendingSnapShotIds.length > 0 ||6478 pendingSnapShotIds.length > 0 ||
6479 expandedComposerImages.some((image) => image.source?.kind === "snap-shot")6479 expandedComposerImages.some((image) => image.source?.kind === "snap-shot")
6480 ? "snap-x snap-proximity overflow-x-auto overscroll-x-contain pb-1 [scrollbar-color:color-mix(in_srgb,var(--contrast-foreground)_18%,transparent)_transparent] [scrollbar-width:thin] [&::-webkit-scrollbar]:h-2.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:border-3 [&::-webkit-scrollbar-thumb]:border-transparent [&::-webkit-scrollbar-thumb]:bg-[color-mix(in_srgb,var(--contrast-foreground)_18%,transparent)] [&::-webkit-scrollbar-thumb]:bg-clip-content [&::-webkit-scrollbar-thumb:hover]:bg-[color-mix(in_srgb,var(--contrast-foreground)_28%,transparent)] [&::-webkit-scrollbar-track]:mx-1 [&::-webkit-scrollbar-track]:bg-transparent"6480 ? "snap-x snap-proximity overflow-x-auto overscroll-x-contain pb-1 scrollbar-thumb-foreground/18 scrollbar-track-transparent [scrollbar-width:thin] [&::-webkit-scrollbar]:h-2.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:border-3 [&::-webkit-scrollbar-thumb]:border-transparent [&::-webkit-scrollbar-thumb]:bg-foreground/18 [&::-webkit-scrollbar-thumb]:bg-clip-content [&::-webkit-scrollbar-thumb:hover]:bg-foreground/28 [&::-webkit-scrollbar-track]:mx-1 [&::-webkit-scrollbar-track]:bg-transparent"
6481 : "flex-wrap",6481 : "flex-wrap",
6482 )}6482 )}
6483 >6483 >
...@@ -6532,14 +6532,14 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6532,14 +6532,14 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6532 alt={image.name}6532 alt={image.name}
6533 className="h-full w-full object-cover"6533 className="h-full w-full object-cover"
6534 fallback={6534 fallback={
6535 <span className="flex h-full items-center justify-center px-1 text-[10px] text-secondary-label">6535 <span className="flex h-full items-center justify-center px-1 text-3xs text-secondary-label">
6536 {image.name}6536 {image.name}
6537 </span>6537 </span>
6538 }6538 }
6539 />6539 />
6540 </button>6540 </button>
6541 ) : (6541 ) : (
6542 <div className="flex h-full w-full items-center justify-center px-1 text-center text-[10px] text-secondary-label">6542 <div className="flex h-full w-full items-center justify-center px-1 text-center text-3xs text-secondary-label">
6543 {image.name}6543 {image.name}
6544 </div>6544 </div>
6545 )}6545 )}
...@@ -6572,7 +6572,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6572,7 +6572,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6572 </Tooltip>6572 </Tooltip>
6573 )}6573 )}
6574 {upload?.status === "uploading" && (6574 {upload?.status === "uploading" && (
6575 <span className="pointer-events-none absolute inset-x-0 bottom-0 bg-background/85 px-1 text-center text-[10px] text-foreground">6575 <span className="pointer-events-none absolute inset-x-0 bottom-0 bg-background/85 px-1 text-center text-3xs text-foreground">
6576 {formatAttachmentUploadProgress(upload.progress)}6576 {formatAttachmentUploadProgress(upload.progress)}
6577 </span>6577 </span>
6578 )}6578 )}
...@@ -6671,7 +6671,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)...@@ -6671,7 +6671,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
6671 <PlayIcon className="relative z-10 size-4 fill-current drop-shadow-md" />6671 <PlayIcon className="relative z-10 size-4 fill-current drop-shadow-md" />
6672 </button>6672 </button>
6673 {upload?.status === "uploading" && (6673 {upload?.status === "uploading" && (
6674 <span className="pointer-events-none absolute inset-x-0 bottom-0 bg-background/85 px-1 text-center text-[10px] text-foreground">6674 <span className="pointer-events-none absolute inset-x-0 bottom-0 bg-background/85 px-1 text-center text-3xs text-foreground">
6675 {formatAttachmentUploadProgress(upload.progress)}6675 {formatAttachmentUploadProgress(upload.progress)}
6676 </span>6676 </span>
6677 )}6677 )}
apps/web/src/components/chat/ChatHeader.tsx+2-2
...@@ -494,8 +494,8 @@ export const ChatHeader = memo(function ChatHeader({...@@ -494,8 +494,8 @@ export const ChatHeader = memo(function ChatHeader({
494 "flex shrink-0 items-center justify-end gap-2 @3xl/header-actions:gap-3",494 "flex shrink-0 items-center justify-end gap-2 @3xl/header-actions:gap-3",
495 // Reserve two panel toggles plus their 4px gaps and 1px edge inset.495 // Reserve two panel toggles plus their 4px gaps and 1px edge inset.
496 // The page header adds 8px more right padding at sm.496 // The page header adds 8px more right padding at sm.
497 rightPanelOpen ? "pr-0" : "pr-[calc(--spacing(18)+1px)] sm:pr-[calc(--spacing(14)+1px)]",497 rightPanelOpen ? "pr-0" : "pr-18.25 sm:pr-14.25",
498 "[[data-panel-animations=true]_&]:motion-safe:transition-[padding-right] [[data-panel-animations=true]_&]:motion-safe:[transition-duration:var(--panel-animation-duration)] [[data-panel-animations=true]_&]:motion-safe:ease-out",498 "[[data-panel-animations=true]_&]:motion-safe:transition-[padding-right] [[data-panel-animations=true]_&]:motion-safe:duration-(--panel-animation-duration) [[data-panel-animations=true]_&]:motion-safe:ease-out",
499 )}499 )}
500 >500 >
501 <Menu open={actionsCollapsed && actionsOpen} onOpenChange={setActionsOpen}>501 <Menu open={actionsCollapsed && actionsOpen} onOpenChange={setActionsOpen}>
apps/web/src/components/chat/ComposerBanner.tsx+14-22
...@@ -51,17 +51,17 @@ function Surface({...@@ -51,17 +51,17 @@ function Surface({
51 surfaceColors,51 surfaceColors,
52 "relative isolate border-0 bg-transparent shadow-none [--chat-composer-attached-tint:transparent]",52 "relative isolate border-0 bg-transparent shadow-none [--chat-composer-attached-tint:transparent]",
53 variantColors[variant],53 variantColors[variant],
54 // The mask cut-off (1rem) bleeds one pixel past the seam (1rem + 1px): Chromium
55 // drops the last device-pixel row of a filtered backdrop when the cut-off lands
56 // off the device-pixel grid, and the composer's surface starts exactly there.
57 // The composer's own glass covers the extra row, so the overlap never shows.
54 placement === "attached"58 placement === "attached"
55 ? "[--chat-composer-attachment-overlap:calc(1rem+1px)] before:rounded-t-[16px]"59 ? "[--chat-composer-attachment-overlap:calc(1rem+1px)] before:rounded-t-2xl before:mask-t-from-transparent before:mask-t-from-4 before:mask-t-to-black before:mask-t-to-4"
56 : "[--chat-composer-attachment-overlap:0px] before:rounded-[1rem]",60 : "[--chat-composer-attachment-overlap:0px] before:rounded-2xl",
57 "before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:border before:border-(--chat-composer-attached-outline)",61 "before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:border before:border-(--chat-composer-attached-outline)",
58 "before:bg-[color-mix(in_srgb,var(--chat-composer-attached-surface)_var(--glass-opacity),transparent)] before:bg-[linear-gradient(var(--chat-composer-attached-tint),var(--chat-composer-attached-tint))] before:backdrop-blur-(--glass-blur) before:backdrop-saturate-(--glass-saturation)",62 "before:bg-(--chat-composer-attached-surface)/(--glass-opacity) before:bg-linear-to-b before:from-(--chat-composer-attached-tint) before:to-(--chat-composer-attached-tint) before:backdrop-blur-(--glass-blur) before:backdrop-saturate-(--glass-saturation)",
59 // The mask cut-off bleeds one pixel past the seam: Chromium drops the last63 "before:shadow-composer dark:before:shadow-composer-dark",
60 // device-pixel row of a filtered backdrop when the cut-off lands off the64 "dark:supports-[(backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px))]:before:bg-composer-seam-above",
61 // device-pixel grid, and the composer's surface starts exactly there. The
62 // composer's own glass covers the extra row, so the overlap never shows.
63 "before:mask-[linear-gradient(to_top,transparent_0_calc(var(--chat-composer-attachment-overlap)-1px),black_calc(var(--chat-composer-attachment-overlap)-1px))] before:shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)] dark:before:shadow-[0_14px_32px_-18px_rgb(0_0_0/75%)]",
64 "dark:supports-[(backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px))]:before:bg-[linear-gradient(var(--chat-composer-attached-tint),var(--chat-composer-attached-tint)),linear-gradient(to_top,transparent_0_var(--chat-composer-attachment-overlap),rgb(0_0_0/18%)_var(--chat-composer-attachment-overlap),transparent_calc(var(--chat-composer-attachment-overlap)+10px))]",
65 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:before:bg-(--chat-composer-attached-surface)",65 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:before:bg-(--chat-composer-attached-surface)",
66 className,66 className,
67 )}67 )}
...@@ -91,8 +91,8 @@ function Peek({...@@ -91,8 +91,8 @@ function Peek({
91 className={cn(91 className={cn(
92 surfaceColors,92 surfaceColors,
93 neutralOutline,93 neutralOutline,
94 "absolute inset-x-0 bottom-0 z-0 mx-auto h-3 w-[96%] cursor-pointer rounded-t-2xl border border-b-0 shadow-[0_6px_18px_rgb(0_0_0/6%)]",94 "absolute inset-x-0 bottom-0 z-0 mx-auto h-3 w-[96%] cursor-pointer rounded-t-2xl border border-b-0 shadow-md",
95 "bg-[color-mix(in_srgb,var(--chat-composer-attached-surface)_var(--glass-opacity),transparent)] backdrop-blur-(--glass-blur) backdrop-saturate-(--glass-saturation)",95 "bg-(--chat-composer-attached-surface)/(--glass-opacity) backdrop-blur-(--glass-blur) backdrop-saturate-(--glass-saturation)",
96 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:bg-(--chat-composer-attached-surface)",96 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:bg-(--chat-composer-attached-surface)",
97 "transition-opacity duration-150 ease-out focus-visible:outline-2 focus-visible:outline-ring",97 "transition-opacity duration-150 ease-out focus-visible:outline-2 focus-visible:outline-ring",
98 peekBorder[variant],98 peekBorder[variant],
...@@ -161,7 +161,7 @@ function Root({...@@ -161,7 +161,7 @@ function Root({
161 return (161 return (
162 <Surface162 <Surface
163 className={cn(163 className={cn(
164 "min-w-0 px-1 pt-(--composer-banner-padding-block) pb-[calc(var(--chat-composer-attachment-overlap)+var(--composer-banner-padding-block))] text-xs/4 [--composer-banner-icon-column:--spacing(7)] [--composer-banner-padding-block:--spacing(1)] sm:[--composer-banner-icon-column:--spacing(6)]",164 "min-w-0 px-1 py-(--composer-banner-padding-block) after:block after:h-(--chat-composer-attachment-overlap) text-xs/4 [--composer-banner-icon-column:--spacing(7)] [--composer-banner-padding-block:--spacing(1)] sm:[--composer-banner-icon-column:--spacing(6)]",
165 density === "comfortable" && "[--composer-banner-padding-block:--spacing(1.25)]",165 density === "comfortable" && "[--composer-banner-padding-block:--spacing(1.25)]",
166 density === "spacious" && "px-3 [--composer-banner-padding-block:--spacing(3)]",166 density === "spacious" && "px-3 [--composer-banner-padding-block:--spacing(3)]",
167 width === "content" ? "w-fit max-w-full flex-none" : "@container",167 width === "content" ? "w-fit max-w-full flex-none" : "@container",
...@@ -189,7 +189,7 @@ function Row({...@@ -189,7 +189,7 @@ function Row({
189 className: cn(189 className: cn(
190 "group/banner-row grid min-h-(--composer-banner-icon-column) w-full min-w-0 grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)_auto] items-center gap-x-1 text-start",190 "group/banner-row grid min-h-(--composer-banner-icon-column) w-full min-w-0 grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)_auto] items-center gap-x-1 text-start",
191 "not-has-[>[data-slot=composer-banner-actions]]:grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)]",191 "not-has-[>[data-slot=composer-banner-actions]]:grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)]",
192 "[&:is(button)]:cursor-pointer [&:is(button)]:rounded-[0.5rem] [&:is(button)]:focus-visible:outline-2 [&:is(button)]:focus-visible:-outline-offset-2 [&:is(button)]:focus-visible:outline-ring",192 "[&:is(button)]:cursor-pointer [&:is(button)]:rounded-md [&:is(button)]:focus-visible:outline-2 [&:is(button)]:focus-visible:-outline-offset-2 [&:is(button)]:focus-visible:outline-ring",
193 layout === "wrap-actions" &&193 layout === "wrap-actions" &&
194 "@max-[400px]:*:data-[slot=composer-banner-content]:min-h-(--composer-banner-icon-column)",194 "@max-[400px]:*:data-[slot=composer-banner-content]:min-h-(--composer-banner-icon-column)",
195 layout === "wrap-actions-narrow" &&195 layout === "wrap-actions-narrow" &&
...@@ -306,15 +306,7 @@ function Count({ className, ...props }: ComponentProps<"span">) {...@@ -306,15 +306,7 @@ function Count({ className, ...props }: ComponentProps<"span">) {
306}306}
307307
308function Body({ className, ...props }: ComponentProps<"div">) {308function Body({ className, ...props }: ComponentProps<"div">) {
309 return (309 return <div className={cn("min-w-0 ps-8 sm:ps-7", className)} {...props} />;
310 <div
311 className={cn(
312 "min-w-0 ps-[calc(var(--composer-banner-icon-column)+(--spacing(1)))]",
313 className,
314 )}
315 {...props}
316 />
317 );
318}310}
319311
320function Dot({ className, ...props }: ComponentProps<"span">) {312function Dot({ className, ...props }: ComponentProps<"span">) {
apps/web/src/components/chat/ComposerBannerStack.tsx+2-2
...@@ -123,7 +123,7 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro...@@ -123,7 +123,7 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro
123 <div123 <div
124 key={frontItem.id}124 key={frontItem.id}
125 className={cn(125 className={cn(
126 "relative z-10 transition-[translate,opacity] duration-220 ease-in",126 "relative z-10 transition-[opacity,translate] duration-220 ease-in",
127 exitingItemId === frontItem.id127 exitingItemId === frontItem.id
128 ? "pointer-events-none translate-y-16 opacity-0"128 ? "pointer-events-none translate-y-16 opacity-0"
129 : "opacity-100",129 : "opacity-100",
...@@ -218,7 +218,7 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro...@@ -218,7 +218,7 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro
218 <div218 <div
219 key={item.id}219 key={item.id}
220 className={cn(220 className={cn(
221 "transition-[translate,opacity] duration-220 ease-in",221 "transition-[opacity,translate] duration-220 ease-in",
222 exitingItemId === item.id222 exitingItemId === item.id
223 ? "pointer-events-none translate-y-28 opacity-0"223 ? "pointer-events-none translate-y-28 opacity-0"
224 : "opacity-100",224 : "opacity-100",
apps/web/src/components/chat/ComposerControl.tsx+3-3
...@@ -16,10 +16,10 @@ export type ComposerControlSize = "sm" | "xs";...@@ -16,10 +16,10 @@ export type ComposerControlSize = "sm" | "xs";
16 */16 */
17function composerControlClassName(size: ComposerControlSize, className?: string) {17function composerControlClassName(size: ComposerControlSize, className?: string) {
18 return cn(18 return cn(
19 "relative inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap rounded-[var(--control-radius)] border border-transparent text-base outline-none hover:bg-accent data-pressed:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-disabled:pointer-events-none data-disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&:active:not([aria-haspopup])]:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:-mx-0.5 [&_svg[data-composer-control-icon]]:mx-0 [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)]",19 "relative inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap rounded-(--control-radius) border border-transparent text-base outline-none hover:bg-accent data-pressed:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-disabled:pointer-events-none data-disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&:active:not([aria-haspopup])]:scale-[0.97] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:-mx-0.5 [&_svg[data-composer-control-icon]]:mx-0",
20 size === "xs"20 size === "xs"
21 ? "h-7 gap-1 px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-sm [--control-icon-color:currentColor] hover:text-foreground/80 sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg[data-composer-control-chevron]]:ms-0 [&_svg[data-composer-control-chevron]]:-me-1"21 ? "h-7 gap-1 px-1.75 font-normal text-muted-foreground/70 text-sm hover:text-foreground/80 sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg[data-composer-control-chevron]]:ms-0 [&_svg[data-composer-control-chevron]]:-me-1"
22 : "h-7 gap-1.5 px-2.5 font-medium text-secondary-label [--control-icon-color:var(--contrast-muted-foreground)] hover:text-foreground sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4",22 : "h-7 gap-1.5 px-2.5 font-medium text-secondary-label [&_svg:not([class*='text-'])]:text-muted-foreground hover:text-foreground sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4",
23 "aria-pressed:bg-accent aria-pressed:text-accent-foreground aria-pressed:hover:bg-accent/80",23 "aria-pressed:bg-accent aria-pressed:text-accent-foreground aria-pressed:hover:bg-accent/80",
24 className,24 className,
25 );25 );
apps/web/src/components/chat/ComposerPendingApprovalPanel.tsx+1-1
...@@ -41,7 +41,7 @@ export const ComposerPendingApprovalPanel = memo(function ComposerPendingApprova...@@ -41,7 +41,7 @@ export const ComposerPendingApprovalPanel = memo(function ComposerPendingApprova
41 className={cn("flex min-w-0 flex-1 flex-col items-start gap-1", className)}41 className={cn("flex min-w-0 flex-1 flex-col items-start gap-1", className)}
42 role="group"42 role="group"
43 >43 >
44 <span className="flex w-full min-w-0 items-center gap-2 text-[11px] text-muted-foreground">44 <span className="flex w-full min-w-0 items-center gap-2 text-2xs text-muted-foreground">
45 <span className="shrink-0 font-medium text-warning">{fallbackLabel}</span>45 <span className="shrink-0 font-medium text-warning">{fallbackLabel}</span>
46 {approval.appName ? <span className="min-w-0 truncate">{approval.appName}</span> : null}46 {approval.appName ? <span className="min-w-0 truncate">{approval.appName}</span> : null}
47 {pendingCount > 1 ? (47 {pendingCount > 1 ? (
apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx+3-5
...@@ -198,7 +198,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(...@@ -198,7 +198,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
198 </ComposerBanner.Content>198 </ComposerBanner.Content>
199 <ComposerBanner.Actions>199 <ComposerBanner.Actions>
200 {prompt.questions.length > 1 ? (200 {prompt.questions.length > 1 ? (
201 <span className="text-[10px] font-medium text-muted-foreground tabular-nums">201 <span className="text-3xs font-medium text-muted-foreground tabular-nums">
202 {questionIndex + 1}/{prompt.questions.length}202 {questionIndex + 1}/{prompt.questions.length}
203 </span>203 </span>
204 ) : null}204 ) : null}
...@@ -257,9 +257,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(...@@ -257,9 +257,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
257 <div className="min-w-0 flex-1 flex flex-col gap-0.5">257 <div className="min-w-0 flex-1 flex flex-col gap-0.5">
258 <span className="text-sm font-medium">{option.label}</span>258 <span className="text-sm font-medium">{option.label}</span>
259 {option.description && option.description !== option.label ? (259 {option.description && option.description !== option.label ? (
260 <span className="text-secondary-label text-[11px]">260 <span className="text-secondary-label text-2xs">{option.description}</span>
261 {option.description}
262 </span>
263 ) : null}261 ) : null}
264 </div>262 </div>
265 {isSelected ? (263 {isSelected ? (
...@@ -267,7 +265,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(...@@ -267,7 +265,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
267 ) : shortcutKey !== null ? (265 ) : shortcutKey !== null ? (
268 <kbd266 <kbd
269 className={cn(267 className={cn(
270 "flex size-5 shrink-0 items-center justify-center text-[10px] font-medium text-muted-foreground tabular-nums",268 "flex size-5 shrink-0 items-center justify-center text-3xs font-medium text-muted-foreground tabular-nums",
271 )}269 )}
272 >270 >
273 {shortcutKey}271 {shortcutKey}
apps/web/src/components/chat/ComposerPrimaryActions.tsx+2-2
...@@ -91,7 +91,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({...@@ -91,7 +91,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
91 <button91 <button
92 type="button"92 type="button"
93 className={cn(93 className={cn(
94 "flex cursor-pointer items-center justify-center rounded-full bg-destructive/90 text-white shadow-xs shadow-destructive/24 inset-shadow-[0_1px_--theme(--color-white/16%)] transition-all duration-150 hover:bg-destructive hover:scale-105 active:inset-shadow-[0_1px_--theme(--color-black/8%)] active:shadow-none",94 "flex cursor-pointer items-center justify-center rounded-full bg-destructive/90 text-white shadow-xs shadow-destructive/24 inset-shadow-2xs inset-shadow-white/16 transition-all duration-150 hover:bg-destructive hover:scale-105 active:inset-shadow-black/8 active:shadow-none",
95 insidePendingAction95 insidePendingAction
96 ? "size-8 sm:size-7"96 ? "size-8 sm:size-7"
97 : hasSendableContent97 : hasSendableContent
...@@ -215,7 +215,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({...@@ -215,7 +215,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
215 <button215 <button
216 type="submit"216 type="submit"
217 className={cn(217 className={cn(
218 "relative isolate flex h-9 w-9 items-center justify-center overflow-hidden rounded-full shadow-xs transition-all duration-150 enabled:cursor-pointer enabled:inset-shadow-[0_1px_--theme(--color-white/16%)] hover:scale-105 active:inset-shadow-[0_1px_--theme(--color-black/8%)] active:shadow-none disabled:pointer-events-none disabled:opacity-30 disabled:shadow-none disabled:hover:scale-100 sm:h-8 sm:w-8",218 "relative isolate flex h-9 w-9 items-center justify-center overflow-hidden rounded-full shadow-xs transition-all duration-150 enabled:cursor-pointer enabled:inset-shadow-2xs enabled:inset-shadow-white/16 hover:scale-105 active:inset-shadow-black/8 active:shadow-none disabled:pointer-events-none disabled:opacity-30 disabled:shadow-none disabled:hover:scale-100 sm:h-8 sm:w-8",
219 stageBackdropVariant219 stageBackdropVariant
220 ? "bg-transparent text-white enabled:shadow-black/24 enabled:hover:brightness-110"220 ? "bg-transparent text-white enabled:shadow-black/24 enabled:hover:brightness-110"
221 : "bg-message-action text-message-action-foreground enabled:shadow-message-action/24 hover:bg-message-action-hover",221 : "bg-message-action text-message-action-foreground enabled:shadow-message-action/24 hover:bg-message-action-hover",
apps/web/src/components/chat/ComposerStashBadge.tsx+1-1
...@@ -25,7 +25,7 @@ export const ComposerStashBadge = memo(function ComposerStashBadge(props: {...@@ -25,7 +25,7 @@ export const ComposerStashBadge = memo(function ComposerStashBadge(props: {
25 key={props.pulseKey}25 key={props.pulseKey}
26 className={cn(26 className={cn(
27 props.pulsing27 props.pulsing
28 ? "animate-[prompt-stash-count-enter_180ms_ease-out_both] text-primary motion-reduce:animate-none"28 ? "text-primary transition-[opacity,translate] duration-180 ease-out starting:translate-y-0.5 starting:opacity-0 motion-reduce:transition-none"
29 : "text-muted-foreground",29 : "text-muted-foreground",
30 )}30 )}
31 >31 >
apps/web/src/components/chat/ComposerSurface.tsx+10-10
...@@ -19,7 +19,7 @@ function Shell({...@@ -19,7 +19,7 @@ function Shell({
19 "[html[data-theme-id]_&]:[--chat-composer-glass-surface:var(--app-theme-surface-raised)] [html[data-theme-id]_&]:[--chat-composer-outline:var(--app-theme-toolbar-border)]",19 "[html[data-theme-id]_&]:[--chat-composer-glass-surface:var(--app-theme-surface-raised)] [html[data-theme-id]_&]:[--chat-composer-outline:var(--app-theme-toolbar-border)]",
20 "dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-highlight:color-mix(in_srgb,var(--app-theme-input)_12%,transparent)] dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-outline:color-mix(in_srgb,var(--app-theme-input)_30%,var(--background))]",20 "dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-highlight:color-mix(in_srgb,var(--app-theme-input)_12%,transparent)] dark:[html[data-theme-id]:not([data-theme-id=t3-chat])_&]:[--chat-composer-outline:color-mix(in_srgb,var(--app-theme-input)_30%,var(--background))]",
21 "dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-highlight:color-mix(in_srgb,#432d48_12%,transparent)] dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-outline:#241e28]",21 "dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-highlight:color-mix(in_srgb,#432d48_12%,transparent)] dark:[html[data-theme-id=t3-chat]_&]:[--chat-composer-outline:#241e28]",
22 "before:pointer-events-none before:absolute before:inset-0 before:z-0 before:rounded-[22px] before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] before:backdrop-blur-(--glass-blur) before:backdrop-saturate-(--glass-saturation)",22 "before:pointer-events-none before:absolute before:inset-0 before:z-0 before:rounded-3xl before:bg-(--chat-composer-glass-surface)/(--glass-opacity) before:backdrop-blur-(--glass-blur) before:backdrop-saturate-(--glass-saturation)",
23 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:before:bg-(--chat-composer-glass-surface)",23 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:before:bg-(--chat-composer-glass-surface)",
24 "has-data-[composer-banner-surface=attached]:before:hidden",24 "has-data-[composer-banner-surface=attached]:before:hidden",
25 contextStrip && [25 contextStrip && [
...@@ -37,7 +37,7 @@ function Shell({...@@ -37,7 +37,7 @@ function Shell({
37}37}
3838
39const outlineClasses =39const outlineClasses =
40 "after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-(--chat-composer-outline) dark:after:shadow-[inset_0_1px_var(--chat-composer-highlight)]";40 "after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-(--chat-composer-outline) dark:after:inset-shadow-2xs dark:after:inset-shadow-(color:--chat-composer-highlight)";
4141
42// The bottom strip continues the outline, so leave the seam between its corners open.42// The bottom strip continues the outline, so leave the seam between its corners open.
43const contextSeamClasses =43const contextSeamClasses =
...@@ -48,7 +48,7 @@ function Host({ className, ...props }: ComponentProps<"div">) {...@@ -48,7 +48,7 @@ function Host({ className, ...props }: ComponentProps<"div">) {
48 <div48 <div
49 data-slot="composer-host"49 data-slot="composer-host"
50 className={cn(50 className={cn(
51 "relative z-10 w-full rounded-[22px] shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)] after:z-1 dark:shadow-none",51 "relative z-10 w-full rounded-3xl shadow-composer after:z-1 dark:shadow-none",
52 outlineClasses,52 outlineClasses,
53 contextSeamClasses,53 contextSeamClasses,
54 "group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-none group-has-data-[composer-banner-surface=attached]/composer-surface:after:hidden",54 "group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-none group-has-data-[composer-banner-surface=attached]/composer-surface:after:hidden",
...@@ -64,12 +64,12 @@ function Main({ className, ...props }: ComponentProps<"div">) {...@@ -64,12 +64,12 @@ function Main({ className, ...props }: ComponentProps<"div">) {
64 <div64 <div
65 data-chat-composer-main-surface="true"65 data-chat-composer-main-surface="true"
66 className={cn(66 className={cn(
67 "group relative z-10 rounded-[22px] p-px transition-colors duration-200",67 "group relative z-10 rounded-3xl p-px transition-colors duration-200",
68 outlineClasses,68 outlineClasses,
69 contextSeamClasses,69 contextSeamClasses,
70 "after:z-20 after:hidden group-has-data-[composer-banner-surface=attached]/composer-surface:after:block",70 "after:z-20 after:hidden group-has-data-[composer-banner-surface=attached]/composer-surface:after:block",
71 "group-has-data-[composer-banner-surface=attached]/composer-surface:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] group-has-data-[composer-banner-surface=attached]/composer-surface:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:backdrop-saturate-(--glass-saturation)",71 "group-has-data-[composer-banner-surface=attached]/composer-surface:bg-(--chat-composer-glass-surface)/(--glass-opacity) group-has-data-[composer-banner-surface=attached]/composer-surface:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:backdrop-saturate-(--glass-saturation)",
72 "group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)] dark:group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-none",72 "group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-composer dark:group-has-data-[composer-banner-surface=attached]/composer-surface:shadow-none",
73 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:group-has-data-[composer-banner-surface=attached]/composer-surface:bg-(--chat-composer-glass-surface)",73 "not-supports-[((backdrop-filter:blur(1px))_or_(-webkit-backdrop-filter:blur(1px)))]:group-has-data-[composer-banner-surface=attached]/composer-surface:bg-(--chat-composer-glass-surface)",
74 "group-has-data-[composer-banner-surface=attached]/composer-surface:**:data-[chat-composer-mobile-collapsed=true]:min-h-[calc(1rem+1px)]",74 "group-has-data-[composer-banner-surface=attached]/composer-surface:**:data-[chat-composer-mobile-collapsed=true]:min-h-[calc(1rem+1px)]",
75 className,75 className,
...@@ -85,10 +85,10 @@ function ContextStrip({ className, ...props }: ComponentProps<"div">) {...@@ -85,10 +85,10 @@ function ContextStrip({ className, ...props }: ComponentProps<"div">) {
85 data-slot="composer-context-strip"85 data-slot="composer-context-strip"
86 className={cn(86 className={cn(
87 "group/composer-context relative isolate mx-auto -mt-4 flex w-[calc(100%-2*var(--chat-composer-drawer-inset))] items-center gap-2 overflow-x-clip overflow-y-visible ps-1 pe-2 pt-5 pb-1",87 "group/composer-context relative isolate mx-auto -mt-4 flex w-[calc(100%-2*var(--chat-composer-drawer-inset))] items-center gap-2 overflow-x-clip overflow-y-visible ps-1 pe-2 pt-5 pb-1",
88 "before:absolute before:inset-0 before:-z-1 before:rounded-b-[16px] before:border before:border-(--chat-composer-outline) before:mask-[linear-gradient(to_bottom,transparent_0_1rem,black_1rem)] before:shadow-[0_12px_28px_-18px_rgb(0_0_0/40%)]",88 "before:absolute before:inset-0 before:-z-1 before:rounded-b-2xl before:border before:border-(--chat-composer-outline) before:mask-b-from-transparent before:mask-b-from-4 before:mask-b-to-black before:mask-b-to-4 before:shadow-composer",
89 "dark:before:border-white/7 dark:before:bg-[linear-gradient(to_bottom,transparent_0_1rem,rgb(0_0_0/18%)_1rem,transparent_calc(1rem+10px)),linear-gradient(rgb(255_255_255/1%),rgb(255_255_255/1%))] dark:before:shadow-[0_14px_32px_-18px_rgb(0_0_0/75%)]",89 "dark:before:border-white/7 dark:before:bg-composer-seam-below dark:before:shadow-composer-dark",
90 "group-has-data-[composer-banner-surface=attached]/composer-surface:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-saturate-(--glass-saturation)",90 "group-has-data-[composer-banner-surface=attached]/composer-surface:before:bg-(--chat-composer-glass-surface)/(--glass-opacity) group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-blur-(--glass-blur) group-has-data-[composer-banner-surface=attached]/composer-surface:before:backdrop-saturate-(--glass-saturation)",
91 "not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:bg-[color-mix(in_srgb,var(--chat-composer-glass-surface)_var(--glass-opacity),transparent)] not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-blur-(--glass-blur) not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-saturate-(--glass-saturation)",91 "not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:bg-(--chat-composer-glass-surface)/(--glass-opacity) not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-blur-(--glass-blur) not-supports-[clip-path:shape(from_0_0,line_to_1px_1px)]:before:backdrop-saturate-(--glass-saturation)",
92 className,92 className,
93 )}93 )}
94 {...props}94 {...props}
apps/web/src/components/chat/ComposerTasksBadge.tsx+1-1
...@@ -200,7 +200,7 @@ export const ComposerTasksContent = memo(function ComposerTasksContent({...@@ -200,7 +200,7 @@ export const ComposerTasksContent = memo(function ComposerTasksContent({
200 </ComposerBanner.Content>200 </ComposerBanner.Content>
201 <ComposerBanner.Actions>201 <ComposerBanner.Actions>
202 <span202 <span
203 className="w-12 text-right text-[10px]/4 text-muted-foreground/45 tabular-nums"203 className="w-12 text-right text-3xs/4 text-muted-foreground/45 tabular-nums"
204 data-composer-task-duration="true"204 data-composer-task-duration="true"
205 >205 >
206 {step.durationMs !== undefined206 {step.durationMs !== undefined
apps/web/src/components/chat/ContextWindowMeter.tsx+6-6
...@@ -92,11 +92,11 @@ export function ContextWindowMeter(props: {...@@ -92,11 +92,11 @@ export function ContextWindowMeter(props: {
92 width="sm"92 width="sm"
93 className="text-left whitespace-normal"93 className="text-left whitespace-normal"
94 >94 >
95 <div className="flex flex-col gap-2 p-[var(--floating-content-inset)]">95 <div className="flex flex-col gap-2 p-(--floating-content-inset)">
96 <div className="flex items-center justify-between gap-3">96 <div className="flex items-center justify-between gap-3">
97 <div className="font-medium text-muted-foreground text-xs">Context Window</div>97 <div className="font-medium text-muted-foreground text-xs">Context Window</div>
98 {usage.maxTokens !== null && usedPercentage ? (98 {usage.maxTokens !== null && usedPercentage ? (
99 <div className="text-secondary-label text-[11px] tabular-nums">99 <div className="text-secondary-label text-2xs tabular-nums">
100 <span>{usedPercentage}</span>100 <span>{usedPercentage}</span>
101 <span className="mx-1">·</span>101 <span className="mx-1">·</span>
102 <span>102 <span>
...@@ -105,7 +105,7 @@ export function ContextWindowMeter(props: {...@@ -105,7 +105,7 @@ export function ContextWindowMeter(props: {
105 </span>105 </span>
106 </div>106 </div>
107 ) : (107 ) : (
108 <div className="text-secondary-label text-[11px] tabular-nums">108 <div className="text-secondary-label text-2xs tabular-nums">
109 {formatContextWindowTokens(usage.usedTokens)}109 {formatContextWindowTokens(usage.usedTokens)}
110 </div>110 </div>
111 )}111 )}
...@@ -126,7 +126,7 @@ export function ContextWindowMeter(props: {...@@ -126,7 +126,7 @@ export function ContextWindowMeter(props: {
126 </div>126 </div>
127 ) : null}127 ) : null}
128 {showTotalProcessed ? (128 {showTotalProcessed ? (
129 <div className="flex items-center justify-between gap-3 text-[11px] leading-4">129 <div className="flex items-center justify-between gap-3 text-2xs leading-4">
130 <span className="text-secondary-label">Total processed</span>130 <span className="text-secondary-label">Total processed</span>
131 <span className="font-medium tabular-nums text-secondary-label">131 <span className="font-medium tabular-nums text-secondary-label">
132 {formatContextWindowTokens(totalProcessedTokens)}132 {formatContextWindowTokens(totalProcessedTokens)}
...@@ -134,7 +134,7 @@ export function ContextWindowMeter(props: {...@@ -134,7 +134,7 @@ export function ContextWindowMeter(props: {
134 </div>134 </div>
135 ) : null}135 ) : null}
136 {usage.compactsAutomatically ? (136 {usage.compactsAutomatically ? (
137 <div className="mt-1 text-pretty text-secondary-label text-[11px] font-medium">137 <div className="mt-1 text-pretty text-secondary-label text-2xs font-medium">
138 {formatContextWindowCompactionMessage(modelDisplayName, usage.autoCompactThreshold)}138 {formatContextWindowCompactionMessage(modelDisplayName, usage.autoCompactThreshold)}
139 </div>139 </div>
140 ) : null}140 ) : null}
...@@ -151,7 +151,7 @@ export function ContextWindowMeter(props: {...@@ -151,7 +151,7 @@ export function ContextWindowMeter(props: {
151 Compact context151 Compact context
152 </Button>152 </Button>
153 {compactDisabled && compactDisabledReason ? (153 {compactDisabled && compactDisabledReason ? (
154 <div className="text-pretty text-secondary-label text-[11px]">154 <div className="text-pretty text-secondary-label text-2xs">
155 {compactDisabledReason}155 {compactDisabledReason}
156 </div>156 </div>
157 ) : null}157 ) : null}
apps/web/src/components/chat/ExpandedImageDialog.tsx+1-1
...@@ -219,7 +219,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({...@@ -219,7 +219,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
219 accessibilityDetails ? (219 accessibilityDetails ? (
220 <SnapShotAccessibilityData220 <SnapShotAccessibilityData
221 details={accessibilityDetails}221 details={accessibilityDetails}
222 className="h-[min(var(--media-height),40rem)] w-[min(var(--media-width),42rem)] animate-[snap-shot-contents-enter_140ms_ease-out] rounded-lg border border-border/70 bg-background p-4 text-xs leading-5 shadow-2xl motion-reduce:animate-none"222 className="h-[min(var(--media-height),40rem)] w-[min(var(--media-width),42rem)] transition-opacity duration-140 ease-out starting:opacity-0 rounded-lg border border-border/70 bg-background p-4 text-xs leading-5 shadow-2xl motion-reduce:transition-none"
223 />223 />
224 ) : null224 ) : null
225 ) : item.src === null || failedImageSrc === item.src ? (225 ) : item.src === null || failedImageSrc === item.src ? (
apps/web/src/components/chat/MessagesTimeline.tsx+22-22
...@@ -344,7 +344,7 @@ function TimelineLoadEarlierHeader({...@@ -344,7 +344,7 @@ function TimelineLoadEarlierHeader({
344 fade: boolean;344 fade: boolean;
345}) {345}) {
346 return (346 return (
347 <div className={fade ? "pt-[var(--workspace-titlebar-scroll-fade-height)]" : "pt-3 sm:pt-4"}>347 <div className={fade ? "pt-(--workspace-titlebar-scroll-fade-height)" : "pt-3 sm:pt-4"}>
348 <div className="mx-auto w-full max-w-3xl pb-2">348 <div className="mx-auto w-full max-w-3xl pb-2">
349 <button349 <button
350 type="button"350 type="button"
...@@ -1539,7 +1539,7 @@ function TimelineMinimap({...@@ -1539,7 +1539,7 @@ function TimelineMinimap({
1539 <span1539 <span
1540 aria-hidden="true"1540 aria-hidden="true"
1541 className={cn(1541 className={cn(
1542 "pointer-events-none absolute left-0 h-0.5 -translate-y-1/2 rounded-full bg-muted-foreground/35 transition-[background-color,width] duration-150 data-[in-view=true]:bg-foreground/90",1542 "pointer-events-none absolute left-0 h-0.5 -translate-y-1/2 rounded-full bg-muted-foreground/35 transition-[width,background-color] duration-150 data-[in-view=true]:bg-foreground/90",
1543 activeDistance === 01543 activeDistance === 0
1544 ? "w-6 bg-muted-foreground/75"1544 ? "w-6 bg-muted-foreground/75"
1545 : activeDistance === 11545 : activeDistance === 1
...@@ -1885,7 +1885,7 @@ function UserVideoAttachment({ file }: { readonly file: ChatFileAttachment }) {...@@ -1885,7 +1885,7 @@ function UserVideoAttachment({ file }: { readonly file: ChatFileAttachment }) {
18851885
1886 if (asset === null && src === null) {1886 if (asset === null && src === null) {
1887 return (1887 return (
1888 <div className="flex aspect-[4/3] w-full items-center justify-center rounded-lg border border-border/80 bg-black px-2 py-3 text-center text-[11px] text-white/70">1888 <div className="flex aspect-[4/3] w-full items-center justify-center rounded-lg border border-border/80 bg-black px-2 py-3 text-center text-2xs text-white/70">
1889 {file.name}1889 {file.name}
1890 </div>1890 </div>
1891 );1891 );
...@@ -2112,7 +2112,7 @@ function UserTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "message"...@@ -2112,7 +2112,7 @@ function UserTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "message"
2112 />2112 />
2113 </button>2113 </button>
2114 ) : (2114 ) : (
2115 <div className="flex min-h-[72px] items-center justify-center px-2 py-3 text-center text-secondary-label text-[11px]">2115 <div className="flex min-h-[72px] items-center justify-center px-2 py-3 text-center text-secondary-label text-2xs">
2116 {image.name}2116 {image.name}
2117 </div>2117 </div>
2118 )}2118 )}
...@@ -2756,7 +2756,7 @@ function ReasoningTraceBlock({...@@ -2756,7 +2756,7 @@ function ReasoningTraceBlock({
2756 className="flex min-h-6 cursor-pointer select-none items-center gap-1.5 rounded-md px-0.5 text-start text-sm leading-relaxed transition-colors hover:bg-accent/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"2756 className="flex min-h-6 cursor-pointer select-none items-center gap-1.5 rounded-md px-0.5 text-start text-sm leading-relaxed transition-colors hover:bg-accent/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"
2757 >2757 >
2758 <span className="flex size-6 shrink-0 items-center justify-center text-icon-muted">2758 <span className="flex size-6 shrink-0 items-center justify-center text-icon-muted">
2759 <BrainIcon aria-hidden className="block size-4 shrink-0 stroke-[1.8] opacity-70" />2759 <BrainIcon aria-hidden className="block size-4 shrink-0 stroke-2 opacity-70" />
2760 </span>2760 </span>
2761 <span2761 <span
2762 ref={streaming ? observeVisibleAnimation : undefined}2762 ref={streaming ? observeVisibleAnimation : undefined}
...@@ -2829,7 +2829,7 @@ const ReasoningTimelineRow = memo(function ReasoningTimelineRow({...@@ -2829,7 +2829,7 @@ const ReasoningTimelineRow = memo(function ReasoningTimelineRow({
2829 className="flex cursor-pointer select-none items-center gap-1.5 rounded-md px-0.5 py-0.5 text-start transition-colors hover:bg-accent/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"2829 className="flex cursor-pointer select-none items-center gap-1.5 rounded-md px-0.5 py-0.5 text-start transition-colors hover:bg-accent/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"
2830 >2830 >
2831 <span className="flex size-6 shrink-0 items-center justify-center text-icon-muted">2831 <span className="flex size-6 shrink-0 items-center justify-center text-icon-muted">
2832 <BrainIcon aria-hidden className="block size-4 shrink-0 stroke-[1.8] opacity-70" />2832 <BrainIcon aria-hidden className="block size-4 shrink-0 stroke-2 opacity-70" />
2833 </span>2833 </span>
2834 <span className="flex min-w-0 flex-1 items-center gap-1.5">2834 <span className="flex min-w-0 flex-1 items-center gap-1.5">
2835 <span className="relative min-w-0 flex-1 truncate text-secondary-label text-sm leading-relaxed">2835 <span className="relative min-w-0 flex-1 truncate text-secondary-label text-sm leading-relaxed">
...@@ -3208,7 +3208,7 @@ function LiveActivityContent({...@@ -3208,7 +3208,7 @@ function LiveActivityContent({
3208 <ToolActivityIconView3208 <ToolActivityIconView
3209 icon={toolIcon}3209 icon={toolIcon}
3210 fallbackName={iconName}3210 fallbackName={iconName}
3211 className="block size-4 shrink-0 stroke-[1.8]"3211 className="block size-4 shrink-0 stroke-2"
3212 muted={!highlighted}3212 muted={!highlighted}
3213 />3213 />
3214 </span>3214 </span>
...@@ -3329,7 +3329,7 @@ function WorkGroupToggleTimelineRow({...@@ -3329,7 +3329,7 @@ function WorkGroupToggleTimelineRow({
3329 fallbackName={3329 fallbackName={
3330 row.summaryToolIcon ?? row.toolSurface ?? toolGroupSummaryIconName(row.summaryKind)3330 row.summaryToolIcon ?? row.toolSurface ?? toolGroupSummaryIconName(row.summaryKind)
3331 }3331 }
3332 className="size-4 shrink-0 stroke-[1.8]"3332 className="size-4 shrink-0 stroke-2"
3333 muted3333 muted
3334 />3334 />
3335 </span>3335 </span>
...@@ -3545,7 +3545,7 @@ function UserMessagePreviewAnnotationDetails(props: {...@@ -3545,7 +3545,7 @@ function UserMessagePreviewAnnotationDetails(props: {
3545 {props.record.comment}3545 {props.record.comment}
3546 </div>3546 </div>
3547 ) : null}3547 ) : null}
3548 <div className="mt-1 flex items-center gap-2 text-secondary-label text-[10px]">3548 <div className="mt-1 flex items-center gap-2 text-secondary-label text-3xs">
3549 {props.record.targetSummary ? (3549 {props.record.targetSummary ? (
3550 <span className="truncate">{props.record.targetSummary}</span>3550 <span className="truncate">{props.record.targetSummary}</span>
3551 ) : null}3551 ) : null}
...@@ -3577,7 +3577,7 @@ function UserMessagePreviewAnnotationDetails(props: {...@@ -3577,7 +3577,7 @@ function UserMessagePreviewAnnotationDetails(props: {
3577 ) : null}3577 ) : null}
3578 </div>3578 </div>
3579 {element.htmlPreview?.trim() ? (3579 {element.htmlPreview?.trim() ? (
3580 <pre className="mt-1 max-h-24 overflow-auto whitespace-pre-wrap rounded bg-muted/60 px-2 py-1.5 text-[10px] leading-relaxed">3580 <pre className="mt-1 max-h-24 overflow-auto whitespace-pre-wrap rounded bg-muted/60 px-2 py-1.5 text-3xs leading-relaxed">
3581 {element.htmlPreview.trim()}3581 {element.htmlPreview.trim()}
3582 </pre>3582 </pre>
3583 ) : null}3583 ) : null}
...@@ -3585,7 +3585,7 @@ function UserMessagePreviewAnnotationDetails(props: {...@@ -3585,7 +3585,7 @@ function UserMessagePreviewAnnotationDetails(props: {
3585 );3585 );
3586 })}3586 })}
3587 {(props.record.elements?.length ?? 0) > visibleElements.length ? (3587 {(props.record.elements?.length ?? 0) > visibleElements.length ? (
3588 <div className="text-secondary-label text-[10px]">3588 <div className="text-secondary-label text-3xs">
3589 {(props.record.elements?.length ?? 0) - visibleElements.length} more selected3589 {(props.record.elements?.length ?? 0) - visibleElements.length} more selected
3590 elements3590 elements
3591 </div>3591 </div>
...@@ -3611,7 +3611,7 @@ function UserMessageElementDetails({...@@ -3611,7 +3611,7 @@ function UserMessageElementDetails({
3611 <div className="truncate text-message-foreground text-xs font-medium">3611 <div className="truncate text-message-foreground text-xs font-medium">
3612 {record.pageTitle?.trim() || record.pageUrl}3612 {record.pageTitle?.trim() || record.pageUrl}
3613 </div>3613 </div>
3614 <div className="mt-0.5 truncate text-secondary-label text-[10px]">{record.pageUrl}</div>3614 <div className="mt-0.5 truncate text-secondary-label text-3xs">{record.pageUrl}</div>
3615 </div>3615 </div>
3616 <div className="space-y-2 px-3 py-2.5">3616 <div className="space-y-2 px-3 py-2.5">
3617 <div className="flex min-w-0 items-center gap-2 text-xs">3617 <div className="flex min-w-0 items-center gap-2 text-xs">
...@@ -4013,7 +4013,7 @@ function UserMessageReviewCommentCard({ comment }: { comment: ReviewCommentConte...@@ -4013,7 +4013,7 @@ function UserMessageReviewCommentCard({ comment }: { comment: ReviewCommentConte
4013 <div className="text-message-foreground text-xs font-medium">4013 <div className="text-message-foreground text-xs font-medium">
4014 {formatWorkspaceRelativePath(comment.filePath, ctx.workspaceRoot)}4014 {formatWorkspaceRelativePath(comment.filePath, ctx.workspaceRoot)}
4015 </div>4015 </div>
4016 <div className="text-secondary-label text-[11px]">4016 <div className="text-secondary-label text-2xs">
4017 {comment.sectionTitle} · {comment.rangeLabel}4017 {comment.sectionTitle} · {comment.rangeLabel}
4018 </div>4018 </div>
4019 </div>4019 </div>
...@@ -4153,7 +4153,7 @@ function ToolActivityIconView(props: {...@@ -4153,7 +4153,7 @@ function ToolActivityIconView(props: {
4153 muted: boolean;4153 muted: boolean;
4154}) {4154}) {
4155 const { resolvedTheme } = use(TimelineRowCtx);4155 const { resolvedTheme } = use(TimelineRowCtx);
4156 const fallbackClassName = cn(props.className, props.muted && "opacity-70 light:brightness-[.6]");4156 const fallbackClassName = cn(props.className, props.muted && "opacity-70 light:brightness-60");
4157 if (!props.icon) {4157 if (!props.icon) {
4158 return <WorkEntryIcon name={props.fallbackName} className={fallbackClassName} />;4158 return <WorkEntryIcon name={props.fallbackName} className={fallbackClassName} />;
4159 }4159 }
...@@ -4213,7 +4213,7 @@ function NativeAppToolActivityIcon(props: {...@@ -4213,7 +4213,7 @@ function NativeAppToolActivityIcon(props: {
4213 return (4213 return (
4214 <WorkEntryIcon4214 <WorkEntryIcon
4215 name={props.fallbackName}4215 name={props.fallbackName}
4216 className={cn(props.className, props.muted && "opacity-70 light:brightness-[.6]")}4216 className={cn(props.className, props.muted && "opacity-70 light:brightness-60")}
4217 />4217 />
4218 );4218 );
4219 }4219 }
...@@ -4258,14 +4258,14 @@ function ToolActivityImageIcon(props: {...@@ -4258,14 +4258,14 @@ function ToolActivityImageIcon(props: {
4258 {displayedSrc === null ? (4258 {displayedSrc === null ? (
4259 <WorkEntryIcon4259 <WorkEntryIcon
4260 name={props.fallbackName}4260 name={props.fallbackName}
4261 className={cn(props.className, props.muted && "opacity-70 light:brightness-[.6]")}4261 className={cn(props.className, props.muted && "opacity-70 light:brightness-60")}
4262 />4262 />
4263 ) : null}4263 ) : null}
4264 {displayedSrc ? (4264 {displayedSrc ? (
4265 <span4265 <span
4266 className={cn(4266 className={cn(
4267 props.className,4267 props.className,
4268 "inline-block overflow-hidden rounded-[3px] bg-background",4268 "inline-block overflow-hidden rounded-xs bg-background",
4269 props.muted && "opacity-70",4269 props.muted && "opacity-70",
4270 )}4270 )}
4271 >4271 >
...@@ -4275,7 +4275,7 @@ function ToolActivityImageIcon(props: {...@@ -4275,7 +4275,7 @@ function ToolActivityImageIcon(props: {
4275 aria-hidden4275 aria-hidden
4276 decoding="async"4276 decoding="async"
4277 referrerPolicy="no-referrer"4277 referrerPolicy="no-referrer"
4278 className={cn("block size-full object-contain", props.muted && "light:brightness-[.6]")}4278 className={cn("block size-full object-contain", props.muted && "light:brightness-60")}
4279 onError={() => handleLoadError(displayedSrc)}4279 onError={() => handleLoadError(displayedSrc)}
4280 />4280 />
4281 </span>4281 </span>
...@@ -4429,7 +4429,7 @@ function buildToolCallExpandedBody(...@@ -4429,7 +4429,7 @@ function buildToolCallExpandedBody(
4429}4429}
44304430
4431const toolCallExpandedBodyClassName =4431const toolCallExpandedBodyClassName =
4432 "max-h-64 cursor-text overflow-auto whitespace-pre-wrap break-words font-mono text-secondary-label text-[length:var(--font-size-code,0.6875rem)] leading-relaxed select-text";4432 "max-h-64 cursor-text overflow-auto whitespace-pre-wrap break-words font-mono text-secondary-label text-(length:--font-size-code,var(--text-2xs)) leading-relaxed select-text";
44334433
4434function workEntryIconName(workEntry: TimelineWorkEntry): WorkEntryIconName {4434function workEntryIconName(workEntry: TimelineWorkEntry): WorkEntryIconName {
4435 if (4435 if (
...@@ -4640,12 +4640,12 @@ function AgentSpawnMemberRow({...@@ -4640,12 +4640,12 @@ function AgentSpawnMemberRow({
4640 {agent.title}4640 {agent.title}
4641 </span>4641 </span>
4642 {role ? (4642 {role ? (
4643 <span className="max-w-28 shrink-0 truncate rounded-sm border border-border/60 px-1 font-mono text-[.65rem] text-muted-foreground">4643 <span className="max-w-28 shrink-0 truncate rounded-sm border border-border/60 px-1 font-mono text-3xs text-muted-foreground">
4644 {role}4644 {role}
4645 </span>4645 </span>
4646 ) : null}4646 ) : null}
4647 </p>4647 </p>
4648 <span className="shrink-0 font-mono text-[.7rem] tabular-nums text-muted-foreground">4648 <span className="shrink-0 font-mono text-2xs tabular-nums text-muted-foreground">
4649 {statusLabel}4649 {statusLabel}
4650 </span>4650 </span>
4651 </div>4651 </div>
...@@ -4821,7 +4821,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: {...@@ -4821,7 +4821,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: {
4821 <ToolActivityIconView4821 <ToolActivityIconView
4822 icon={entryToolIcon}4822 icon={entryToolIcon}
4823 fallbackName={entryIconName}4823 fallbackName={entryIconName}
4824 className="block size-4 shrink-0 stroke-[1.8]"4824 className="block size-4 shrink-0 stroke-2"
4825 muted4825 muted
4826 />4826 />
4827 </span>4827 </span>
apps/web/src/components/chat/ModelListRow.tsx+1-1
...@@ -70,7 +70,7 @@ export const ModelListRow = memo(function ModelListRow(props: {...@@ -70,7 +70,7 @@ export const ModelListRow = memo(function ModelListRow(props: {
70 </div>70 </div>
71 {props.showNewBadge ? (71 {props.showNewBadge ? (
72 <span72 <span
73 className="shrink-0 rounded border border-update/35 bg-update/15 px-0.5 py-px text-[10px] font-bold uppercase leading-none tracking-wide text-update-foreground"73 className="shrink-0 rounded border border-update/35 bg-update/15 px-0.5 py-px text-3xs font-bold uppercase leading-none tracking-wide text-update-foreground"
74 aria-label="New model"74 aria-label="New model"
75 >75 >
76 New76 New
apps/web/src/components/chat/ModelPickerSidebar.tsx+3-5
...@@ -123,7 +123,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {...@@ -123,7 +123,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {
123 render={123 render={
124 <Toolbar.Button124 <Toolbar.Button
125 className={cn(125 className={cn(
126 "relative isolate flex w-full cursor-pointer aspect-square items-center justify-center rounded-md transition-colors hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] focus-visible:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] focus-visible:outline-none",126 "relative isolate flex w-full cursor-pointer aspect-square items-center justify-center rounded-md transition-colors hover:bg-foreground/10 focus-visible:bg-foreground/10 focus-visible:outline-none",
127 )}127 )}
128 onClick={() => handleSelect("favorites")}128 onClick={() => handleSelect("favorites")}
129 type="button"129 type="button"
...@@ -171,7 +171,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {...@@ -171,7 +171,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {
171 const button = (171 const button = (
172 <Toolbar.Button172 <Toolbar.Button
173 className={cn(173 className={cn(
174 "relative isolate flex w-full cursor-pointer aspect-square items-center justify-center rounded-md transition-colors hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] focus-visible:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] focus-visible:outline-none",174 "relative isolate flex w-full cursor-pointer aspect-square items-center justify-center rounded-md transition-colors hover:bg-foreground/10 focus-visible:bg-foreground/10 focus-visible:outline-none",
175 isDisabled && "opacity-50 cursor-not-allowed hover:bg-transparent",175 isDisabled && "opacity-50 cursor-not-allowed hover:bg-transparent",
176 )}176 )}
177 data-provider-accent-color={entry.accentColor}177 data-provider-accent-color={entry.accentColor}
...@@ -210,9 +210,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {...@@ -210,9 +210,7 @@ export const ModelPickerSidebar = memo(function ModelPickerSidebar(props: {
210 ? "var(--background)"210 ? "var(--background)"
211 : "color-mix(in oklab, var(--muted) 30%, transparent)"211 : "color-mix(in oklab, var(--muted) 30%, transparent)"
212 }212 }
213 {...(entry.accentColor213 {...(entry.accentColor ? { badgeClassName: "h-3 min-w-3 px-0.5 text-3xs" } : {})}
214 ? { badgeClassName: "h-3 min-w-3 px-0.5 text-[7px]" }
215 : {})}
216 />214 />
217 {showNewBadge ? (215 {showNewBadge ? (
218 <span className={NEW_BADGE_CLASS} aria-hidden>216 <span className={NEW_BADGE_CLASS} aria-hidden>
apps/web/src/components/chat/PanelLayoutControls.tsx+1-1
...@@ -78,7 +78,7 @@ export const PanelLayoutControls = memo(function PanelLayoutControls({...@@ -78,7 +78,7 @@ export const PanelLayoutControls = memo(function PanelLayoutControls({
78 {liveAgentCount > 0 ? (78 {liveAgentCount > 0 ? (
79 <span79 <span
80 aria-hidden80 aria-hidden
81 className="absolute -top-1 -right-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-[9px] font-semibold tabular-nums text-white"81 className="absolute -top-1 -right-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-3xs font-semibold tabular-nums text-white"
82 >82 >
83 {liveAgentCount}83 {liveAgentCount}
84 </span>84 </span>
apps/web/src/components/chat/ProposedPlanCard.tsx+1-1
...@@ -146,7 +146,7 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({...@@ -146,7 +146,7 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({
146 };146 };
147147
148 return (148 return (
149 <div className="rounded-[24px] border border-border/80 bg-card/70 p-4 sm:p-5">149 <div className="rounded-3xl border border-border/80 bg-card/70 p-4 sm:p-5">
150 <div className="flex flex-wrap items-center justify-between gap-3">150 <div className="flex flex-wrap items-center justify-between gap-3">
151 <div className="flex min-w-0 items-center gap-2">151 <div className="flex min-w-0 items-center gap-2">
152 <Badge variant="secondary">Plan</Badge>152 <Badge variant="secondary">Plan</Badge>
apps/web/src/components/chat/ProviderInstanceIcon.tsx+3-3
...@@ -38,7 +38,7 @@ export const ProviderInstanceIcon = memo(function ProviderInstanceIcon(props: {...@@ -38,7 +38,7 @@ export const ProviderInstanceIcon = memo(function ProviderInstanceIcon(props: {
38 {Icon ? (38 {Icon ? (
39 <Icon className={cn("size-5 shrink-0", props.iconClassName)} aria-hidden />39 <Icon className={cn("size-5 shrink-0", props.iconClassName)} aria-hidden />
40 ) : (40 ) : (
41 <span className={cn("text-[10px] font-semibold leading-none", props.iconClassName)}>41 <span className={cn("text-3xs font-semibold leading-none", props.iconClassName)}>
42 {providerInstanceInitials(props.displayName)}42 {providerInstanceInitials(props.displayName)}
43 </span>43 </span>
44 )}44 )}
...@@ -55,9 +55,9 @@ export const ProviderInstanceIcon = memo(function ProviderInstanceIcon(props: {...@@ -55,9 +55,9 @@ export const ProviderInstanceIcon = memo(function ProviderInstanceIcon(props: {
55 {props.showBadge ? (55 {props.showBadge ? (
56 <span56 <span
57 className={cn(57 className={cn(
58 "pointer-events-none absolute right-0 bottom-0 z-10 flex h-3.5 min-w-3.5 items-center justify-center rounded-full border px-0.5 text-[8px] font-semibold leading-none shadow-sm",58 "pointer-events-none absolute right-0 bottom-0 z-10 flex h-3.5 min-w-3.5 items-center justify-center rounded-full border px-0.5 text-3xs font-semibold leading-none shadow-sm",
59 props.accentColor59 props.accentColor
60 ? "bg-[var(--provider-accent)] text-white"60 ? "bg-(--provider-accent) text-white"
61 : "bg-card text-muted-foreground",61 : "bg-card text-muted-foreground",
62 props.badgeClassName,62 props.badgeClassName,
63 )}63 )}
apps/web/src/components/chat/ProviderModelPicker.test.tsx+1-1
...@@ -174,6 +174,6 @@ describe("ProviderModelPicker", () => {...@@ -174,6 +174,6 @@ describe("ProviderModelPicker", () => {
174 expect(markup).toContain(">CP</span>");174 expect(markup).toContain(">CP</span>");
175 expect(markup).toContain("size-4");175 expect(markup).toContain("size-4");
176 expect(markup).toContain("h-3");176 expect(markup).toContain("h-3");
177 expect(markup).toContain("text-[7px]");177 expect(markup).toContain("text-3xs");
178 });178 });
179});179});
apps/web/src/components/chat/ProviderModelPicker.tsx+3-3
...@@ -229,13 +229,13 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -229,13 +229,13 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {
229 driverKind={selection.entry.driverKind}229 driverKind={selection.entry.driverKind}
230 displayName={selection.entry.displayName}230 displayName={selection.entry.displayName}
231 accentColor={selection.entry.accentColor}231 accentColor={selection.entry.accentColor}
232 className="size-4 rounded-full bg-[var(--chat-composer-glass-surface,var(--background))] ring-2 ring-[var(--chat-composer-glass-surface,var(--background))]"232 className="size-4 rounded-full bg-(--chat-composer-glass-surface,var(--background)) ring-2 ring-(--chat-composer-glass-surface,var(--background))"
233 iconClassName="size-4"233 iconClassName="size-4"
234 />234 />
235 ) : null,235 ) : null,
236 )}236 )}
237 {selectedEntries.length > 3 ? (237 {selectedEntries.length > 3 ? (
238 <span className="relative z-30 flex size-4 items-center justify-center rounded-full bg-[var(--chat-composer-glass-surface,var(--background))] text-[9px] ring-2 ring-[var(--chat-composer-glass-surface,var(--background))]">238 <span className="relative z-30 flex size-4 items-center justify-center rounded-full bg-(--chat-composer-glass-surface,var(--background)) text-3xs ring-2 ring-(--chat-composer-glass-surface,var(--background))">
239 +{selectedEntries.length - 3}239 +{selectedEntries.length - 3}
240 </span>240 </span>
241 ) : null}241 ) : null}
...@@ -250,7 +250,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -250,7 +250,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {
250 iconClassName={cn("size-4", props.activeProviderIconClassName)}250 iconClassName={cn("size-4", props.activeProviderIconClassName)}
251 indicatorBackground={props.instanceIndicatorBackground ?? "var(--contrast-input)"}251 indicatorBackground={props.instanceIndicatorBackground ?? "var(--contrast-input)"}
252 badgeClassName={cn(252 badgeClassName={cn(
253 "right-[-0.125rem] bottom-[-0.125rem] h-3 min-w-3 px-0.5 text-[7px]",253 "right-[-0.125rem] bottom-[-0.125rem] h-3 min-w-3 px-0.5 text-3xs",
254 size === "xs" && "shadow-none",254 size === "xs" && "shadow-none",
255 )}255 )}
256 />256 />
apps/web/src/components/chat/SnapShotAttachmentDetails.tsx+4-4
...@@ -169,7 +169,7 @@ export function SnapShotContentsButton({...@@ -169,7 +169,7 @@ export function SnapShotContentsButton({
169 {accessibilityDetails ? (169 {accessibilityDetails ? (
170 <SnapShotAccessibilityData170 <SnapShotAccessibilityData
171 details={accessibilityDetails}171 details={accessibilityDetails}
172 className="max-h-64 rounded-md border border-border/70 bg-muted/45 p-2.5 text-[11px] leading-4"172 className="max-h-64 rounded-md border border-border/70 bg-muted/45 p-2.5 text-2xs leading-4"
173 />173 />
174 ) : includesAccessibility ? (174 ) : includesAccessibility ? (
175 <div className="rounded-md border border-border/70 bg-muted/45 p-2.5 text-muted-foreground text-xs leading-4">175 <div className="rounded-md border border-border/70 bg-muted/45 p-2.5 text-muted-foreground text-xs leading-4">
...@@ -204,16 +204,16 @@ export function SnapShotAttachmentDetails({...@@ -204,16 +204,16 @@ export function SnapShotAttachmentDetails({
204 {source.appIconDataUrl ? (204 {source.appIconDataUrl ? (
205 <img src={source.appIconDataUrl} alt="" className="size-7 shrink-0 rounded-md" />205 <img src={source.appIconDataUrl} alt="" className="size-7 shrink-0 rounded-md" />
206 ) : (206 ) : (
207 <div className="flex size-7 shrink-0 items-center justify-center rounded-md bg-white/20 text-[10px] font-medium text-white uppercase">207 <div className="flex size-7 shrink-0 items-center justify-center rounded-md bg-white/20 text-3xs font-medium text-white uppercase">
208 {source.appName.slice(0, 1)}208 {source.appName.slice(0, 1)}
209 </div>209 </div>
210 )}210 )}
211 <div className="min-w-0 flex-1">211 <div className="min-w-0 flex-1">
212 <div className="flex min-w-0 items-center gap-1.5 text-[11px] font-medium leading-3.5 text-white">212 <div className="flex min-w-0 items-center gap-1.5 text-2xs font-medium leading-3.5 text-white">
213 <span className="truncate">{source.appName}</span>213 <span className="truncate">{source.appName}</span>
214 <SnapShotContentsButton source={source} className="pointer-events-auto" />214 <SnapShotContentsButton source={source} className="pointer-events-auto" />
215 </div>215 </div>
216 <div className="truncate text-[9px] leading-3.5 text-white/70">216 <div className="truncate text-3xs leading-3.5 text-white/70">
217 {source.windowTitle || "Captured window"}217 {source.windowTitle || "Captured window"}
218 </div>218 </div>
219 </div>219 </div>
apps/web/src/components/chat/WorktreeSetupCard.tsx+2-2
...@@ -56,7 +56,7 @@ function useNowWhile(active: boolean): number {...@@ -56,7 +56,7 @@ function useNowWhile(active: boolean): number {
56}56}
5757
58function StageIcon({ status }: { status: WorktreeSetupStage["status"] }) {58function StageIcon({ status }: { status: WorktreeSetupStage["status"] }) {
59 const className = "size-4 shrink-0 stroke-[1.8]";59 const className = "size-4 shrink-0 stroke-2";
60 switch (status) {60 switch (status) {
61 case "done":61 case "done":
62 return <CheckIcon aria-hidden className={className} />;62 return <CheckIcon aria-hidden className={className} />;
...@@ -240,7 +240,7 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b...@@ -240,7 +240,7 @@ function OutputTail({ lines, failed }: { lines: ReadonlyArray<string>; failed: b
240 return (240 return (
241 <pre241 <pre
242 className={cn(242 className={cn(
243 "mb-1 ml-8 overflow-hidden rounded-md border px-2.5 py-1.5 font-mono text-[11px] leading-relaxed select-text",243 "mb-1 ml-8 overflow-hidden rounded-md border px-2.5 py-1.5 font-mono text-2xs leading-relaxed select-text",
244 failed244 failed
245 ? "border-destructive/20 bg-error-surface text-destructive-foreground"245 ? "border-destructive/20 bg-error-surface text-destructive-foreground"
246 : "border-border bg-code text-muted-foreground",246 : "border-border bg-code text-muted-foreground",
apps/web/src/components/clerk/ClerkUserProfilePage.tsx+2-2
...@@ -22,9 +22,9 @@ export function ClerkUserProfilePage({...@@ -22,9 +22,9 @@ export function ClerkUserProfilePage({
22 <div className={cn("w-full min-w-0 text-foreground", className)}>22 <div className={cn("w-full min-w-0 text-foreground", className)}>
23 <header className="flex flex-col gap-3 pb-4 sm:flex-row sm:items-start sm:justify-between sm:gap-4 sm:pr-8">23 <header className="flex flex-col gap-3 pb-4 sm:flex-row sm:items-start sm:justify-between sm:gap-4 sm:pr-8">
24 <div className="min-w-0">24 <div className="min-w-0">
25 <h2 className="text-[1.0625rem] leading-6 font-semibold">{title}</h2>25 <h2 className="text-base leading-6 font-semibold">{title}</h2>
26 {description ? (26 {description ? (
27 <p className="mt-1 max-w-[34rem] text-[0.8125rem] leading-[1.125rem] text-muted-foreground sm:min-h-9">27 <p className="mt-1 max-w-[34rem] text-xs leading-4.5 text-muted-foreground sm:min-h-9">
28 {description}28 {description}
29 </p>29 </p>
30 ) : null}30 ) : null}
apps/web/src/components/clerk/MobileClientsUserProfilePage.tsx+5-5
...@@ -38,14 +38,14 @@ function MobileClientRow({ device }: { readonly device: RelayClientDeviceRecord...@@ -38,14 +38,14 @@ function MobileClientRow({ device }: { readonly device: RelayClientDeviceRecord
38 <ClerkUserProfileRow icon={<SmartphoneIcon className="size-4" />}>38 <ClerkUserProfileRow icon={<SmartphoneIcon className="size-4" />}>
39 <div className="flex flex-col gap-0.5 sm:flex-row sm:items-start sm:justify-between sm:gap-3">39 <div className="flex flex-col gap-0.5 sm:flex-row sm:items-start sm:justify-between sm:gap-3">
40 <div className="min-w-0">40 <div className="min-w-0">
41 <h3 className="truncate text-[0.8125rem] leading-[1.125rem] font-medium text-foreground">41 <h3 className="truncate text-sm leading-4.5 font-medium text-foreground">
42 {device.label}42 {device.label}
43 </h3>43 </h3>
44 <p className="text-xs leading-[1.125rem] text-muted-foreground">44 <p className="text-xs leading-4.5 text-muted-foreground">
45 {mobileClientPlatformLabel(device)}45 {mobileClientPlatformLabel(device)}
46 </p>46 </p>
47 </div>47 </div>
48 <p className="shrink-0 text-[0.6875rem] leading-4 text-muted-foreground/75">48 <p className="shrink-0 text-2xs leading-4 text-muted-foreground/75">
49 {mobileClientUpdatedAtLabel(device.updatedAt)}49 {mobileClientUpdatedAtLabel(device.updatedAt)}
50 </p>50 </p>
51 </div>51 </div>
...@@ -56,7 +56,7 @@ function MobileClientRow({ device }: { readonly device: RelayClientDeviceRecord...@@ -56,7 +56,7 @@ function MobileClientRow({ device }: { readonly device: RelayClientDeviceRecord
56 />56 />
57 <MobileClientStatusBadge enabled={device.liveActivities.enabled} label="Live Activities" />57 <MobileClientStatusBadge enabled={device.liveActivities.enabled} label="Live Activities" />
58 </div>58 </div>
59 <p className="mt-1.5 text-xs leading-[1.125rem] text-muted-foreground/80">59 <p className="mt-1.5 text-xs leading-4.5 text-muted-foreground/80">
60 {mobileClientNotificationDetail(device)}60 {mobileClientNotificationDetail(device)}
61 </p>61 </p>
62 </ClerkUserProfileRow>62 </ClerkUserProfileRow>
...@@ -123,7 +123,7 @@ export function MobileClientsUserProfilePage() {...@@ -123,7 +123,7 @@ export function MobileClientsUserProfilePage() {
123 <div>123 <div>
124 {devicesState.error ? (124 {devicesState.error ? (
125 <div125 <div
126 className="mb-4 flex flex-col gap-3 border-t border-destructive/35 py-3 text-[0.8125rem] sm:flex-row sm:items-center sm:justify-between"126 className="mb-4 flex flex-col gap-3 border-t border-destructive/35 py-3 text-xs sm:flex-row sm:items-center sm:justify-between"
127 role="alert"127 role="alert"
128 >128 >
129 <div>129 <div>
apps/web/src/components/clerk/T3ConnectUserProfilePage.tsx+7-7
...@@ -51,10 +51,10 @@ export function T3ConnectEnvironmentRow(props: {...@@ -51,10 +51,10 @@ export function T3ConnectEnvironmentRow(props: {
51 <Collapsible open={props.confirmationOpen} onOpenChange={props.onConfirmationChange}>51 <Collapsible open={props.confirmationOpen} onOpenChange={props.onConfirmationChange}>
52 <div className="flex items-start gap-4">52 <div className="flex items-start gap-4">
53 <div className="min-w-0 flex-1">53 <div className="min-w-0 flex-1">
54 <h3 className="truncate text-[0.8125rem] leading-[1.125rem] font-medium text-foreground">54 <h3 className="truncate text-sm leading-4.5 font-medium text-foreground">
55 {environment.label}55 {environment.label}
56 </h3>56 </h3>
57 <p className="mt-1 text-xs leading-[1.125rem] text-muted-foreground">57 <p className="mt-1 text-xs leading-4.5 text-muted-foreground">
58 {linkedAtLabel(environment.linkedAt)} · {endpointLabel(environment)}58 {linkedAtLabel(environment.linkedAt)} · {endpointLabel(environment)}
59 </p>59 </p>
60 </div>60 </div>
...@@ -74,13 +74,13 @@ export function T3ConnectEnvironmentRow(props: {...@@ -74,13 +74,13 @@ export function T3ConnectEnvironmentRow(props: {
74 role="group"74 role="group"
75 aria-label={`Confirm deregistration of ${environment.label}`}75 aria-label={`Confirm deregistration of ${environment.label}`}
76 >76 >
77 <h4 className="text-[0.8125rem] leading-[1.125rem] font-semibold text-foreground">77 <h4 className="text-sm leading-4.5 font-semibold text-foreground">
78 Deregister server78 Deregister server
79 </h4>79 </h4>
80 <p className="mt-1 text-[0.8125rem] leading-[1.125rem] text-muted-foreground">80 <p className="mt-1 text-xs leading-4.5 text-muted-foreground">
81 “{environment.label}” will be removed from this account.81 “{environment.label}” will be removed from this account.
82 </p>82 </p>
83 <p className="mt-4 max-w-xl text-[0.8125rem] leading-[1.125rem] text-muted-foreground">83 <p className="mt-4 max-w-xl text-xs leading-4.5 text-muted-foreground">
84 T3 Connect access will be revoked, any managed tunnel will be removed, and a host84 T3 Connect access will be revoked, any managed tunnel will be removed, and a host
85 space will become available. Local connections on your devices are not changed.85 space will become available. Local connections on your devices are not changed.
86 </p>86 </p>
...@@ -205,7 +205,7 @@ export function T3ConnectUserProfilePage() {...@@ -205,7 +205,7 @@ export function T3ConnectUserProfilePage() {
205 >205 >
206 <div>206 <div>
207 {environmentsState.error ? (207 {environmentsState.error ? (
208 <div className="mb-4 border-t border-destructive/35 py-3 text-[0.8125rem]" role="alert">208 <div className="mb-4 border-t border-destructive/35 py-3 text-xs" role="alert">
209 <p className="font-medium text-destructive-foreground">209 <p className="font-medium text-destructive-foreground">
210 Could not load T3 Connect environments210 Could not load T3 Connect environments
211 </p>211 </p>
...@@ -214,7 +214,7 @@ export function T3ConnectUserProfilePage() {...@@ -214,7 +214,7 @@ export function T3ConnectUserProfilePage() {
214 ) : null}214 ) : null}
215215
216 {isInitialLoad ? (216 {isInitialLoad ? (
217 <p className="border-t py-4 text-[0.8125rem] text-muted-foreground" role="status">217 <p className="border-t py-4 text-xs text-muted-foreground" role="status">
218 Loading environments…218 Loading environments…
219 </p>219 </p>
220 ) : environments.length > 0 ? (220 ) : environments.length > 0 ? (
apps/web/src/components/cloud/ConnectCliAuthSurface.tsx+1-3
...@@ -23,9 +23,7 @@ function ConnectCliAuthMessage({...@@ -23,9 +23,7 @@ function ConnectCliAuthMessage({
23 return (23 return (
24 <>24 <>
25 {eyebrow ? (25 {eyebrow ? (
26 <p className="text-[10px] font-semibold tracking-[0.18em] text-primary uppercase">26 <p className="text-3xs font-semibold tracking-widest text-primary uppercase">{eyebrow}</p>
27 {eyebrow}
28 </p>
29 ) : null}27 ) : null}
30 <h1 className="mt-2 text-2xl font-semibold tracking-tight sm:text-3xl">{title}</h1>28 <h1 className="mt-2 text-2xl font-semibold tracking-tight sm:text-3xl">{title}</h1>
31 <p className="mt-2 text-sm leading-relaxed text-muted-foreground">{description}</p>29 <p className="mt-2 text-sm leading-relaxed text-muted-foreground">{description}</p>
apps/web/src/components/composerContextPresentation.tsx+1-1
...@@ -269,7 +269,7 @@ function ComposerReviewCommentDetails({ comment }: { comment: ReviewCommentConte...@@ -269,7 +269,7 @@ function ComposerReviewCommentDetails({ comment }: { comment: ReviewCommentConte
269 <div className="space-y-2 overflow-hidden rounded-lg border border-border/70 bg-background/70 p-3">269 <div className="space-y-2 overflow-hidden rounded-lg border border-border/70 bg-background/70 p-3">
270 <div className="space-y-1">270 <div className="space-y-1">
271 <div className="truncate text-xs font-medium text-foreground">{comment.filePath}</div>271 <div className="truncate text-xs font-medium text-foreground">{comment.filePath}</div>
272 <div className="text-secondary-label text-[11px]">272 <div className="text-secondary-label text-2xs">
273 {comment.sectionTitle} · {comment.rangeLabel}273 {comment.sectionTitle} · {comment.rangeLabel}
274 </div>274 </div>
275 </div>275 </div>
apps/web/src/components/contextChipParts.tsx+4-4
...@@ -208,8 +208,8 @@ export function ImageChipButton({...@@ -208,8 +208,8 @@ export function ImageChipButton({
208 <ImageIcon />208 <ImageIcon />
209 )}209 )}
210 <ContextChipLabel className="max-w-72">{middleTruncateAttachmentName(name)}</ContextChipLabel>210 <ContextChipLabel className="max-w-72">{middleTruncateAttachmentName(name)}</ContextChipLabel>
211 <span className="shrink-0 text-[10px] text-current">{size}</span>211 <span className="shrink-0 text-3xs text-current">{size}</span>
212 {suffix ? <span className="text-[10px] text-current">{suffix}</span> : null}212 {suffix ? <span className="text-3xs text-current">{suffix}</span> : null}
213 </ContextChip>213 </ContextChip>
214 );214 );
215}215}
...@@ -284,8 +284,8 @@ function FileChipContent(props: {...@@ -284,8 +284,8 @@ function FileChipContent(props: {
284 <ContextChipLabel className="max-w-72">284 <ContextChipLabel className="max-w-72">
285 {middleTruncateAttachmentName(props.name)}285 {middleTruncateAttachmentName(props.name)}
286 </ContextChipLabel>286 </ContextChipLabel>
287 <span className="shrink-0 text-[10px] text-current">{props.size}</span>287 <span className="shrink-0 text-3xs text-current">{props.size}</span>
288 {props.suffix ? <span className="text-[10px] text-current">{props.suffix}</span> : null}288 {props.suffix ? <span className="text-3xs text-current">{props.suffix}</span> : null}
289 </>289 </>
290 );290 );
291}291}
apps/web/src/components/device/DeviceStreamView.tsx+1-1
...@@ -404,7 +404,7 @@ export function DeviceStreamView(props: {...@@ -404,7 +404,7 @@ export function DeviceStreamView(props: {
404 }}404 }}
405 >405 >
406 {element.label ? (406 {element.label ? (
407 <span className="absolute -top-3.5 left-0 max-w-full truncate rounded-sm bg-info px-1 text-[9px] leading-3.5 text-white">407 <span className="absolute -top-3.5 left-0 max-w-full truncate rounded-sm bg-info px-1 text-3xs leading-3.5 text-white">
408 {element.label}408 {element.label}
409 </span>409 </span>
410 ) : null}410 ) : null}
apps/web/src/components/device/DeviceToolsPanel.tsx+1-1
...@@ -640,7 +640,7 @@ function EventLogSection(props: {...@@ -640,7 +640,7 @@ function EventLogSection(props: {
640 />640 />
641 </CollapsibleTrigger>641 </CollapsibleTrigger>
642 <CollapsiblePanel>642 <CollapsiblePanel>
643 <ol className="max-h-64 overflow-y-auto px-3 py-2 font-mono text-[11px] leading-relaxed">643 <ol className="max-h-64 overflow-y-auto px-3 py-2 font-mono text-2xs leading-relaxed">
644 {entries.length === 0 ? (644 {entries.length === 0 ? (
645 <li className="text-muted-foreground">No events yet.</li>645 <li className="text-muted-foreground">No events yet.</li>
646 ) : (646 ) : (
apps/web/src/components/diffs/DiffCommentAnnotation.tsx+2-2
...@@ -65,7 +65,7 @@ export function DiffCommentAnnotation({...@@ -65,7 +65,7 @@ export function DiffCommentAnnotation({
65 onPointerDown={(event) => event.stopPropagation()}65 onPointerDown={(event) => event.stopPropagation()}
66 >66 >
67 <MessageCircle className="mt-0.5 size-3.5 shrink-0 text-primary/70" aria-hidden="true" />67 <MessageCircle className="mt-0.5 size-3.5 shrink-0 text-primary/70" aria-hidden="true" />
68 <p className="min-w-0 flex-1 whitespace-pre-wrap text-[13px] leading-5">{displayedText}</p>68 <p className="min-w-0 flex-1 whitespace-pre-wrap text-sm leading-5">{displayedText}</p>
69 {onDelete ? (69 {onDelete ? (
70 <span className="-my-1 -mr-1 flex shrink-0 opacity-0 transition-opacity group-hover/comment:opacity-100 focus-within:opacity-100 max-sm:opacity-100">70 <span className="-my-1 -mr-1 flex shrink-0 opacity-0 transition-opacity group-hover/comment:opacity-100 focus-within:opacity-100 max-sm:opacity-100">
71 <Button71 <Button
...@@ -113,7 +113,7 @@ export function DiffCommentAnnotation({...@@ -113,7 +113,7 @@ export function DiffCommentAnnotation({
113 }}113 }}
114 />114 />
115 <div className="mt-1.5 flex items-center gap-1">115 <div className="mt-1.5 flex items-center gap-1">
116 <span className="mr-auto text-[10px] text-muted-foreground/70">⌘/Ctrl Enter to send</span>116 <span className="mr-auto text-3xs text-muted-foreground/70">⌘/Ctrl Enter to send</span>
117 <Button variant="ghost-muted" size="xs" onClick={onCancel}>117 <Button variant="ghost-muted" size="xs" onClick={onCancel}>
118 Cancel118 Cancel
119 </Button>119 </Button>
apps/web/src/components/files/FilePreviewPanel.tsx+1-1
...@@ -1172,7 +1172,7 @@ export default function FilePreviewPanel({...@@ -1172,7 +1172,7 @@ export default function FilePreviewPanel({
1172 !isMedia &&1172 !isMedia &&
1173 !renderBrowserFile &&1173 !renderBrowserFile &&
1174 file.data?.truncated ? (1174 file.data?.truncated ? (
1175 <div className="shrink-0 border-b border-warning/20 bg-warning-surface px-3 py-1.5 text-[11px] text-warning-foreground">1175 <div className="shrink-0 border-b border-warning/20 bg-warning-surface px-3 py-1.5 text-2xs text-warning-foreground">
1176 Preview limited to the first 1 MB of a {file.data.byteLength.toLocaleString()} byte file.1176 Preview limited to the first 1 MB of a {file.data.byteLength.toLocaleString()} byte file.
1177 </div>1177 </div>
1178 ) : null}1178 ) : null}
apps/web/src/components/files/fileSurfaceChrome.tsx+1-1
...@@ -114,7 +114,7 @@ export function FileSurfaceNotice(props: { readonly children: ReactNode }) {...@@ -114,7 +114,7 @@ export function FileSurfaceNotice(props: { readonly children: ReactNode }) {
114 return (114 return (
115 <div115 <div
116 role="status"116 role="status"
117 className="shrink-0 border-b border-warning/20 bg-warning-surface px-3 py-1.5 text-[11px] text-warning-foreground"117 className="shrink-0 border-b border-warning/20 bg-warning-surface px-3 py-1.5 text-2xs text-warning-foreground"
118 >118 >
119 {props.children}119 {props.children}
120 </div>120 </div>
apps/web/src/components/onboarding/WelcomeWizard.tsx+3-5
...@@ -193,7 +193,7 @@ export function WelcomeWizard({...@@ -193,7 +193,7 @@ export function WelcomeWizard({
193 identity={193 identity={
194 <div className="flex items-baseline gap-1.5" role="img" aria-label="T3 Code">194 <div className="flex items-baseline gap-1.5" role="img" aria-label="T3 Code">
195 <T3Wordmark className="h-4 w-auto shrink-0" aria-hidden />195 <T3Wordmark className="h-4 w-auto shrink-0" aria-hidden />
196 <span className="text-[1.4rem] font-medium tracking-tight text-muted-foreground">196 <span className="text-2xl font-medium tracking-tight text-muted-foreground">
197 Code197 Code
198 </span>198 </span>
199 </div>199 </div>
...@@ -892,7 +892,7 @@ function AgentInstallTerminal({...@@ -892,7 +892,7 @@ function AgentInstallTerminal({
892 className="mt-4 overflow-hidden rounded-lg border border-border/70 bg-background text-foreground"892 className="mt-4 overflow-hidden rounded-lg border border-border/70 bg-background text-foreground"
893 >893 >
894 <div className="flex items-center justify-between border-b border-border/60 bg-background/60 px-3 py-1.5">894 <div className="flex items-center justify-between border-b border-border/60 bg-background/60 px-3 py-1.5">
895 <span className="text-[11px] font-medium text-muted-foreground">895 <span className="text-2xs font-medium text-muted-foreground">
896 {setupState === "writeFailed" ? (896 {setupState === "writeFailed" ? (
897 <>897 <>
898 Run <code className="rounded bg-muted px-1 font-mono">{command}</code> in this898 Run <code className="rounded bg-muted px-1 font-mono">{command}</code> in this
...@@ -1445,9 +1445,7 @@ function ImportCandidateRow({...@@ -1445,9 +1445,7 @@ function ImportCandidateRow({
1445 {label}1445 {label}
1446 </span>1446 </span>
1447 {secondary !== undefined ? (1447 {secondary !== undefined ? (
1448 <span className="truncate font-mono text-[11px] text-muted-foreground">1448 <span className="truncate font-mono text-2xs text-muted-foreground">{secondary}</span>
1449 {secondary}
1450 </span>
1451 ) : null}1449 ) : null}
1452 </TooltipTrigger>1450 </TooltipTrigger>
1453 <TooltipPopup variant="code">{candidate.path}</TooltipPopup>1451 <TooltipPopup variant="code">{candidate.path}</TooltipPopup>
apps/web/src/components/preview/AgentBrowserCursor.tsx+1-1
...@@ -55,7 +55,7 @@ function AgentBrowserCursorEvent(props: {...@@ -55,7 +55,7 @@ function AgentBrowserCursorEvent(props: {
5555
56 return (56 return (
57 <div57 <div
58 className="pointer-events-none absolute left-0 top-0 z-40 transition-[transform,opacity] duration-150 ease-out motion-reduce:transition-none"58 className="pointer-events-none absolute left-0 top-0 z-40 transition-[opacity,transform] duration-150 ease-out motion-reduce:transition-none"
59 style={{59 style={{
60 opacity: agentBrowserCursorOpacity(active, controller),60 opacity: agentBrowserCursorOpacity(active, controller),
61 transform: `translate3d(${event.x * zoomFactor * (content?.scale ?? 1) + (content?.x ?? 0) - (content?.scrollLeft ?? 0)}px, ${event.y * zoomFactor * (content?.scale ?? 1) + (content?.y ?? 0) - (content?.scrollTop ?? 0)}px, 0)`,61 transform: `translate3d(${event.x * zoomFactor * (content?.scale ?? 1) + (content?.x ?? 0) - (content?.scrollLeft ?? 0)}px, ${event.y * zoomFactor * (content?.scale ?? 1) + (content?.y ?? 0) - (content?.scrollTop ?? 0)}px, 0)`,
apps/web/src/components/preview/BrowserMockup.tsx+3-3
...@@ -6,16 +6,16 @@ export function BrowserMockup({ className }: { className?: string }) {...@@ -6,16 +6,16 @@ export function BrowserMockup({ className }: { className?: string }) {
6 <div6 <div
7 aria-hidden7 aria-hidden
8 className={cn(8 className={cn(
9 "relative flex flex-col gap-0.5 overflow-hidden rounded-[5px] border border-border/60 bg-card p-1 shadow-xs/5",9 "relative flex flex-col gap-0.5 overflow-hidden rounded-sm border border-border/60 bg-card p-1 shadow-xs/5",
10 className,10 className,
11 )}11 )}
12 >12 >
13 <div className="flex gap-[2px]">13 <div className="flex gap-0.5">
14 <span className="size-[3px] rounded-full bg-destructive/80" />14 <span className="size-[3px] rounded-full bg-destructive/80" />
15 <span className="size-[3px] rounded-full bg-warning/80" />15 <span className="size-[3px] rounded-full bg-warning/80" />
16 <span className="size-[3px] rounded-full bg-success/80" />16 <span className="size-[3px] rounded-full bg-success/80" />
17 </div>17 </div>
18 <div className="mt-[1px] flex flex-1 flex-col gap-[2px]">18 <div className="mt-[1px] flex flex-1 flex-col gap-0.5">
19 <span className="h-[2px] w-full rounded-full bg-muted-foreground/30" />19 <span className="h-[2px] w-full rounded-full bg-muted-foreground/30" />
20 <span className="h-[2px] w-3/5 rounded-full bg-muted-foreground/20" />20 <span className="h-[2px] w-3/5 rounded-full bg-muted-foreground/20" />
21 </div>21 </div>
apps/web/src/components/preview/PreviewPanelShell.tsx+1-1
...@@ -126,7 +126,7 @@ export function PreviewPanelShell(props: {...@@ -126,7 +126,7 @@ export function PreviewPanelShell(props: {
126 : "shrink-0 border-l border-border"126 : "shrink-0 border-l border-border"
127 : "w-full",127 : "w-full",
128 collapsible &&128 collapsible &&
129 "[[data-panel-animations=true]_&]:transition-[width] [[data-panel-animations=true]_&]:[transition-duration:var(--panel-animation-duration)] [[data-panel-animations=true]_&]:ease-out",129 "[[data-panel-animations=true]_&]:transition-[width] [[data-panel-animations=true]_&]:duration-(--panel-animation-duration) [[data-panel-animations=true]_&]:ease-out",
130 collapsible && open && "[[data-panel-animations=true]_&]:starting:w-0!",130 collapsible && open && "[[data-panel-animations=true]_&]:starting:w-0!",
131 collapsible && !open && "pointer-events-none",131 collapsible && !open && "pointer-events-none",
132 )}132 )}
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+2-2
...@@ -828,7 +828,7 @@ function PullRequestCodeTab({...@@ -828,7 +828,7 @@ function PullRequestCodeTab({
828 <PullRequestDiffStat828 <PullRequestDiffStat
829 additions={additions}829 additions={additions}
830 deletions={deletions}830 deletions={deletions}
831 className="font-mono text-[11px]"831 className="font-mono text-2xs"
832 />832 />
833 );833 );
834 const viewedFiles = filesViewedRef.current;834 const viewedFiles = filesViewedRef.current;
...@@ -842,7 +842,7 @@ function PullRequestCodeTab({...@@ -842,7 +842,7 @@ function PullRequestCodeTab({
842 attribute is what the header's capture listener looks for. */}842 attribute is what the header's capture listener looks for. */}
843 <label843 <label
844 data-viewed-toggle=""844 data-viewed-toggle=""
845 className="flex cursor-pointer select-none items-center gap-1.5 text-[11px] text-muted-foreground"845 className="flex cursor-pointer select-none items-center gap-1.5 text-2xs text-muted-foreground"
846 onClick={(event) => event.stopPropagation()}846 onClick={(event) => event.stopPropagation()}
847 >847 >
848 <Checkbox848 <Checkbox
apps/web/src/components/pullRequest/PullRequestComposer.tsx+1-1
...@@ -93,7 +93,7 @@ export function PullRequestComposer({...@@ -93,7 +93,7 @@ export function PullRequestComposer({
93 {pendingComments.length > 0 ? (93 {pendingComments.length > 0 ? (
94 <span94 <span
95 aria-hidden95 aria-hidden
96 className="absolute -top-1 -right-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-[9px] font-semibold tabular-nums text-white"96 className="absolute -top-1 -right-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-info px-1 text-3xs font-semibold tabular-nums text-white"
97 >97 >
98 {pendingComments.length}98 {pendingComments.length}
99 </span>99 </span>
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+4-4
...@@ -2260,7 +2260,7 @@ export function PullRequestDetailPanel({...@@ -2260,7 +2260,7 @@ export function PullRequestDetailPanel({
2260 <span className="shrink-0">{formatRelativeTimeLabel(detail.updatedAt)}</span>2260 <span className="shrink-0">{formatRelativeTimeLabel(detail.updatedAt)}</span>
2261 </span>2261 </span>
2262 <span aria-hidden className="h-3 w-px shrink-0 bg-border/70" />2262 <span aria-hidden className="h-3 w-px shrink-0 bg-border/70" />
2263 <span className="flex min-w-0 flex-1 items-center gap-1.5 font-mono text-[11px] text-muted-foreground/65">2263 <span className="flex min-w-0 flex-1 items-center gap-1.5 font-mono text-2xs text-muted-foreground/65">
2264 {/* An out-of-date base wears the warning on the branch name itself, so the2264 {/* An out-of-date base wears the warning on the branch name itself, so the
2265 name is amber and pointing at either the name or the mark opens the way2265 name is amber and pointing at either the name or the mark opens the way
2266 out. Up to date, the name keeps its plain tooltip. */}2266 out. Up to date, the name keeps its plain tooltip. */}
...@@ -2322,7 +2322,7 @@ export function PullRequestDetailPanel({...@@ -2322,7 +2322,7 @@ export function PullRequestDetailPanel({
2322 <TooltipPopup side="top">{detail.headBranch}</TooltipPopup>2322 <TooltipPopup side="top">{detail.headBranch}</TooltipPopup>
2323 </Tooltip>2323 </Tooltip>
2324 </span>2324 </span>
2325 <span className="ml-auto inline-flex shrink-0 items-center justify-end gap-2 text-[11px]">2325 <span className="ml-auto inline-flex shrink-0 items-center justify-end gap-2 text-2xs">
2326 <span2326 <span
2327 className="inline-flex items-center gap-1 tabular-nums"2327 className="inline-flex items-center gap-1 tabular-nums"
2328 aria-label={`${detail.changedFiles.toLocaleString()} changed ${2328 aria-label={`${detail.changedFiles.toLocaleString()} changed ${
...@@ -2335,7 +2335,7 @@ export function PullRequestDetailPanel({...@@ -2335,7 +2335,7 @@ export function PullRequestDetailPanel({
2335 <PullRequestDiffStat2335 <PullRequestDiffStat
2336 additions={detail.additions}2336 additions={detail.additions}
2337 deletions={detail.deletions}2337 deletions={detail.deletions}
2338 className="shrink-0 font-mono text-[11px]"2338 className="shrink-0 font-mono text-2xs"
2339 />2339 />
2340 </span>2340 </span>
2341 </div>2341 </div>
...@@ -2609,7 +2609,7 @@ export function PullRequestDetailPanel({...@@ -2609,7 +2609,7 @@ export function PullRequestDetailPanel({
2609 <div className="ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground">2609 <div className="ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground">
2610 <PullRequestMetaLine2610 <PullRequestMetaLine
2611 className={cn(2611 className={cn(
2612 "whitespace-nowrap text-[11px] transition-opacity",2612 "whitespace-nowrap text-2xs transition-opacity",
2613 (activityPending || activityError) && "opacity-35",2613 (activityPending || activityError) && "opacity-35",
2614 )}2614 )}
2615 >2615 >
apps/web/src/components/pullRequest/PullRequestLinkPreview.tsx+1-1
...@@ -106,7 +106,7 @@ export function PullRequestLinkPreview({...@@ -106,7 +106,7 @@ export function PullRequestLinkPreview({
106 ))106 ))
107 ) : (107 ) : (
108 <div className="min-w-0">108 <div className="min-w-0">
109 <div className="flex min-w-0 items-center gap-1.5 text-[11px] text-muted-foreground">109 <div className="flex min-w-0 items-center gap-1.5 text-2xs text-muted-foreground">
110 <span className="min-w-0 truncate">{detail.repository}</span>110 <span className="min-w-0 truncate">{detail.repository}</span>
111 <span className="shrink-0">#{detail.number}</span>111 <span className="shrink-0">#{detail.number}</span>
112 <span aria-hidden>·</span>112 <span aria-hidden>·</span>
apps/web/src/components/pullRequest/PullRequestListRow.tsx+4-4
...@@ -68,7 +68,7 @@ export function PullRequestRowGlyph({...@@ -68,7 +68,7 @@ export function PullRequestRowGlyph({
68 />68 />
69 </span>69 </span>
70 </span>70 </span>
71 {below ? <span className="inline-flex text-[11px]">{below}</span> : null}71 {below ? <span className="inline-flex text-2xs">{below}</span> : null}
72 </span>72 </span>
73 );73 );
74}74}
...@@ -100,15 +100,15 @@ export function PullRequestRowLines({...@@ -100,15 +100,15 @@ export function PullRequestRowLines({
100 {number}100 {number}
101 <span className="min-w-0 truncate text-sm">{title}</span>101 <span className="min-w-0 truncate text-sm">{title}</span>
102 {signals ? (102 {signals ? (
103 <span className="flex shrink-0 items-center gap-1 text-[11px]">{signals}</span>103 <span className="flex shrink-0 items-center gap-1 text-2xs">{signals}</span>
104 ) : null}104 ) : null}
105 {status ? (105 {status ? (
106 <span className="ml-auto flex shrink-0 items-center gap-1.5 text-[11px]">{status}</span>106 <span className="ml-auto flex shrink-0 items-center gap-1.5 text-2xs">{status}</span>
107 ) : null}107 ) : null}
108 </span>108 </span>
109 <span109 <span
110 className={cn(110 className={cn(
111 "flex min-w-0 items-center gap-1.5 overflow-hidden text-[11px] text-muted-foreground",111 "flex min-w-0 items-center gap-1.5 overflow-hidden text-2xs text-muted-foreground",
112 metaClassName,112 metaClassName,
113 )}113 )}
114 >114 >
apps/web/src/components/pullRequest/PullRequestRow.tsx+1-1
...@@ -204,7 +204,7 @@ function PullRequestRowImpl({...@@ -204,7 +204,7 @@ function PullRequestRowImpl({
204 <Tooltip>204 <Tooltip>
205 <TooltipTrigger205 <TooltipTrigger
206 render={206 render={
207 <span className="flex min-w-6 items-center gap-1 overflow-hidden rounded-full border border-border/60 px-1 text-[10px]" />207 <span className="flex min-w-6 items-center gap-1 overflow-hidden rounded-full border border-border/60 px-1 text-3xs" />
208 }208 }
209 >209 >
210 <span className="sr-only">matched in the description</span>210 <span className="sr-only">matched in the description</span>
apps/web/src/components/pullRequest/PullRequestSummaryTab.tsx+2-2
...@@ -401,7 +401,7 @@ function CommentGroup({...@@ -401,7 +401,7 @@ function CommentGroup({
401 </span>401 </span>
402 ))}402 ))}
403 {authors.length > 3 ? (403 {authors.length > 3 ? (
404 <span className="relative flex size-6 items-center justify-center rounded-full bg-muted text-[10px] text-muted-foreground ring-2 ring-background">404 <span className="relative flex size-6 items-center justify-center rounded-full bg-muted text-3xs text-muted-foreground ring-2 ring-background">
405 +{authors.length - 3}405 +{authors.length - 3}
406 </span>406 </span>
407 ) : null}407 ) : null}
...@@ -412,7 +412,7 @@ function CommentGroup({...@@ -412,7 +412,7 @@ function CommentGroup({
412 >412 >
413 <span className="min-w-0 flex-1 space-y-1">413 <span className="min-w-0 flex-1 space-y-1">
414 <span className="block text-xs font-medium text-foreground/90">{label}</span>414 <span className="block text-xs font-medium text-foreground/90">{label}</span>
415 <span className="flex flex-wrap gap-x-1.5 text-[11px] text-muted-foreground">415 <span className="flex flex-wrap gap-x-1.5 text-2xs text-muted-foreground">
416 <span>416 <span>
417 {authors.length} {authors.length === 1 ? "author" : "authors"}417 {authors.length} {authors.length === 1 ? "author" : "authors"}
418 </span>418 </span>
apps/web/src/components/pullRequest/PullRequestTimelineTab.tsx+8-10
...@@ -141,7 +141,7 @@ function ActorTimelineMarker({...@@ -141,7 +141,7 @@ function ActorTimelineMarker({
141 <PullRequestActorAvatar141 <PullRequestActorAvatar
142 actor={actor}142 actor={actor}
143 className={cn(143 className={cn(
144 "size-7 bg-muted text-[9px] transition-opacity",144 "size-7 bg-muted text-3xs transition-opacity",
145 muted && "opacity-45 grayscale",145 muted && "opacity-45 grayscale",
146 )}146 )}
147 />147 />
...@@ -156,9 +156,7 @@ function friendlyReviewState(value: string): string {...@@ -156,9 +156,7 @@ function friendlyReviewState(value: string): string {
156156
157function ReviewStateBadge({ state }: { state: string }) {157function ReviewStateBadge({ state }: { state: string }) {
158 return (158 return (
159 <span className="text-[10px] font-medium text-muted-foreground">159 <span className="text-3xs font-medium text-muted-foreground">{friendlyReviewState(state)}</span>
160 {friendlyReviewState(state)}
161 </span>
162 );160 );
163}161}
164162
...@@ -224,7 +222,7 @@ function ConversationCard({...@@ -224,7 +222,7 @@ function ConversationCard({
224 <span className="text-muted-foreground">{event.title}</span>222 <span className="text-muted-foreground">{event.title}</span>
225 {event.reviewState ? <ReviewStateBadge state={event.reviewState} /> : null}223 {event.reviewState ? <ReviewStateBadge state={event.reviewState} /> : null}
226 </div>224 </div>
227 <PullRequestMetaLine className="mt-1 flex-wrap text-[11px] text-muted-foreground">225 <PullRequestMetaLine className="mt-1 flex-wrap text-2xs text-muted-foreground">
228 <span>{formatRelativeTimeLabel(event.at)}</span>226 <span>{formatRelativeTimeLabel(event.at)}</span>
229 {event.path ? (227 {event.path ? (
230 <span className="inline-flex min-w-0 items-center gap-1">228 <span className="inline-flex min-w-0 items-center gap-1">
...@@ -330,7 +328,7 @@ function ConversationGroup({...@@ -330,7 +328,7 @@ function ConversationGroup({
330 <span className="block text-xs font-semibold">328 <span className="block text-xs font-semibold">
331 {events.length.toLocaleString()} {events.length === 1 ? "comment" : "comments"}329 {events.length.toLocaleString()} {events.length === 1 ? "comment" : "comments"}
332 </span>330 </span>
333 <span className="block truncate text-[10px] text-muted-foreground">331 <span className="block truncate text-3xs text-muted-foreground">
334 {actors.length.toLocaleString()} {actors.length === 1 ? "author" : "authors"} ·{" "}332 {actors.length.toLocaleString()} {actors.length === 1 ? "author" : "authors"} ·{" "}
335 {formatRelativeTimeLabel(first.at)}333 {formatRelativeTimeLabel(first.at)}
336 </span>334 </span>
...@@ -391,7 +389,7 @@ function CommitEvent({...@@ -391,7 +389,7 @@ function CommitEvent({
391 <div className="truncate text-xs font-semibold text-foreground transition-colors group-hover:text-primary">389 <div className="truncate text-xs font-semibold text-foreground transition-colors group-hover:text-primary">
392 {event.body ?? "Untitled commit"}390 {event.body ?? "Untitled commit"}
393 </div>391 </div>
394 <div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[10px] text-muted-foreground">392 <div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-3xs text-muted-foreground">
395 <code className="font-mono">{event.id.slice(0, 7)}</code>393 <code className="font-mono">{event.id.slice(0, 7)}</code>
396 <span>{formatRelativeTimeLabel(event.at)}</span>394 <span>{formatRelativeTimeLabel(event.at)}</span>
397 </div>395 </div>
...@@ -400,7 +398,7 @@ function CommitEvent({...@@ -400,7 +398,7 @@ function CommitEvent({
400 <PullRequestDiffStat398 <PullRequestDiffStat
401 additions={event.additions}399 additions={event.additions}
402 deletions={event.deletions}400 deletions={event.deletions}
403 className="ml-auto shrink-0 font-mono text-[10px]"401 className="ml-auto shrink-0 font-mono text-3xs"
404 />402 />
405 ) : null}403 ) : null}
406 </div>404 </div>
...@@ -433,7 +431,7 @@ function LifecycleEvent({ event }: { event: PullRequestTimelineEvent }) {...@@ -433,7 +431,7 @@ function LifecycleEvent({ event }: { event: PullRequestTimelineEvent }) {
433 {event.actor ? <ActorName actor={event.actor} /> : null}431 {event.actor ? <ActorName actor={event.actor} /> : null}
434 <span className="font-semibold text-foreground">{presentation.label}</span>432 <span className="font-semibold text-foreground">{presentation.label}</span>
435 </div>433 </div>
436 <div className="mt-0.5 text-[11px] text-muted-foreground">434 <div className="mt-0.5 text-2xs text-muted-foreground">
437 {formatRelativeTimeLabel(event.at)}435 {formatRelativeTimeLabel(event.at)}
438 </div>436 </div>
439 </div>437 </div>
...@@ -500,7 +498,7 @@ function ReviewVerdictEvent({...@@ -500,7 +498,7 @@ function ReviewVerdictEvent({
500 </Tooltip>498 </Tooltip>
501 </div>499 </div>
502 <div className="mt-0.5 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">500 <div className="mt-0.5 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
503 <PullRequestMetaLine className="flex-wrap text-[11px] text-muted-foreground">501 <PullRequestMetaLine className="flex-wrap text-2xs text-muted-foreground">
504 <span>{formatRelativeTimeLabel(event.at)}</span>502 <span>{formatRelativeTimeLabel(event.at)}</span>
505 {event.path ? (503 {event.path ? (
506 <span className="inline-flex min-w-0 items-center gap-1">504 <span className="inline-flex min-w-0 items-center gap-1">
apps/web/src/components/pullRequest/ThreadPullRequestsPanel.tsx+1-1
...@@ -308,7 +308,7 @@ function EnabledThreadPullRequestsPanel({ threadRef }: { threadRef: ScopedThread...@@ -308,7 +308,7 @@ function EnabledThreadPullRequestsPanel({ threadRef }: { threadRef: ScopedThread
308 ))}308 ))}
309 </div>309 </div>
310 </ScrollArea>310 </ScrollArea>
311 <footer className="flex items-center justify-between border-t border-border/60 px-2 py-1.5 text-[.7rem] text-muted-foreground">311 <footer className="flex items-center justify-between border-t border-border/60 px-2 py-1.5 text-2xs text-muted-foreground">
312 <span>312 <span>
313 {openCount} open · {links.length} linked313 {openCount} open · {links.length} linked
314 {lastSynced ? ` · synced ${formatRelativeTimeLabel(lastSynced)}` : ""}314 {lastSynced ? ` · synced ${formatRelativeTimeLabel(lastSynced)}` : ""}
apps/web/src/components/pullRequest/pullRequestPresentation.tsx+1-1
...@@ -428,7 +428,7 @@ export function PullRequestActorAvatar({...@@ -428,7 +428,7 @@ export function PullRequestActorAvatar({
428 <span428 <span
429 aria-hidden429 aria-hidden
430 className={cn(430 className={cn(
431 "flex size-4 shrink-0 items-center justify-center rounded-full bg-muted text-[8px] font-medium text-muted-foreground",431 "flex size-4 shrink-0 items-center justify-center rounded-full bg-muted text-3xs font-medium text-muted-foreground",
432 className,432 className,
433 )}433 )}
434 >434 >
apps/web/src/components/search/HighlightedSearchLine.tsx+1-1
...@@ -111,7 +111,7 @@ function HighlightedTokens(props: {...@@ -111,7 +111,7 @@ function HighlightedTokens(props: {
111 .map((segment) =>111 .map((segment) =>
112 segment.isMatch ? (112 segment.isMatch ? (
113 <mark113 <mark
114 className="rounded-[2px] bg-primary/25 text-inherit"114 className="rounded-xs bg-primary/25 text-inherit"
115 key={`${segment.start}:${segment.end}:match`}115 key={`${segment.start}:${segment.end}:match`}
116 style={tokenStyle(segment.token)}116 style={tokenStyle(segment.token)}
117 >117 >
apps/web/src/components/search/ProjectContentSearchDialog.tsx+1-1
...@@ -265,7 +265,7 @@ function OpenContentSearchDialog(props: {...@@ -265,7 +265,7 @@ function OpenContentSearchDialog(props: {
265 {path.directory}265 {path.directory}
266 </span>266 </span>
267 ) : null}267 ) : null}
268 <span className="ml-auto rounded-full bg-muted px-1.5 py-0.5 tabular-nums text-[10px] text-muted-foreground">268 <span className="ml-auto rounded-full bg-muted px-1.5 py-0.5 tabular-nums text-3xs text-muted-foreground">
269 {group.matches.length}269 {group.matches.length}
270 </span>270 </span>
271 </div>271 </div>
apps/web/src/components/settings/AddProviderInstanceDialog.tsx+4-4
...@@ -310,7 +310,7 @@ export function AddProviderInstanceDialog({...@@ -310,7 +310,7 @@ export function AddProviderInstanceDialog({
310 value={label}310 value={label}
311 onChange={(event) => setLabel(event.target.value)}311 onChange={(event) => setLabel(event.target.value)}
312 />312 />
313 <span className="text-[11px] text-muted-foreground">313 <span className="text-2xs text-muted-foreground">
314 Shown in the provider list. Optional.314 Shown in the provider list. Optional.
315 </span>315 </span>
316 </label>316 </label>
...@@ -326,9 +326,9 @@ export function AddProviderInstanceDialog({...@@ -326,9 +326,9 @@ export function AddProviderInstanceDialog({
326 aria-invalid={showInstanceIdError}326 aria-invalid={showInstanceIdError}
327 />327 />
328 {showInstanceIdError ? (328 {showInstanceIdError ? (
329 <span className="text-[11px] text-destructive">{instanceIdError}</span>329 <span className="text-2xs text-destructive">{instanceIdError}</span>
330 ) : (330 ) : (
331 <span className="text-[11px] text-muted-foreground">331 <span className="text-2xs text-muted-foreground">
332 Routing key used by threads and sessions. Letters, digits, '-', or '_'.332 Routing key used by threads and sessions. Letters, digits, '-', or '_'.
333 </span>333 </span>
334 )}334 )}
...@@ -374,7 +374,7 @@ export function AddProviderInstanceDialog({...@@ -374,7 +374,7 @@ export function AddProviderInstanceDialog({
374 </Button>374 </Button>
375 ) : null}375 ) : null}
376 </div>376 </div>
377 <span className="text-[11px] text-muted-foreground">377 <span className="text-2xs text-muted-foreground">
378 Optional marker shown in the picker.378 Optional marker shown in the picker.
379 </span>379 </span>
380 </div>380 </div>
apps/web/src/components/settings/ConnectionsSettings.tsx+10-10
...@@ -771,11 +771,11 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -771,11 +771,11 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
771 <AccessScopeSummary scopes={pairingLink.scopes} label="Pairing link scopes" />771 <AccessScopeSummary scopes={pairingLink.scopes} label="Pairing link scopes" />
772 </p>772 </p>
773 {!credential ? (773 {!credential ? (
774 <p className="text-[11px] text-muted-foreground/70">774 <p className="text-2xs text-muted-foreground/70">
775 Create a new link to share from this client.775 Create a new link to share from this client.
776 </p>776 </p>
777 ) : shareablePairingUrl === null ? (777 ) : shareablePairingUrl === null ? (
778 <p className="text-[11px] text-muted-foreground/70">778 <p className="text-2xs text-muted-foreground/70">
779 Copy the token and pair from another client using this backend&apos;s reachable host.779 Copy the token and pair from another client using this backend&apos;s reachable host.
780 </p>780 </p>
781 ) : null}781 ) : null}
...@@ -882,7 +882,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -882,7 +882,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
882 role="radiogroup"882 role="radiogroup"
883 aria-label="Endpoint the pairing QR code and URL use"883 aria-label="Endpoint the pairing QR code and URL use"
884 >884 >
885 <p className="text-[11px] text-muted-foreground/70">Reach this machine via</p>885 <p className="text-2xs text-muted-foreground/70">Reach this machine via</p>
886 {endpointCopyOptions.map((option) => {886 {endpointCopyOptions.map((option) => {
887 const isSelected = option.id === selectedQrOption?.id;887 const isSelected = option.id === selectedQrOption?.id;
888 return (888 return (
...@@ -907,7 +907,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -907,7 +907,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
907 >907 >
908 {option.label}908 {option.label}
909 </span>909 </span>
910 <span className="min-w-0 truncate text-[11px] text-muted-foreground/70">910 <span className="min-w-0 truncate text-2xs text-muted-foreground/70">
911 {option.detail}911 {option.detail}
912 </span>912 </span>
913 </button>913 </button>
...@@ -919,7 +919,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -919,7 +919,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
919 <Tooltip>919 <Tooltip>
920 <TooltipTrigger920 <TooltipTrigger
921 render={921 render={
922 <code className="min-w-0 flex-1 truncate font-mono text-[11px] text-muted-foreground">922 <code className="min-w-0 flex-1 truncate font-mono text-2xs text-muted-foreground">
923 {qrPairingUrl}923 {qrPairingUrl}
924 </code>924 </code>
925 }925 }
...@@ -951,7 +951,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -951,7 +951,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
951 </div>951 </div>
952 ) : (952 ) : (
953 <div className="flex size-[192px] shrink-0 items-center justify-center self-center rounded-xl border border-border/50 p-4 sm:self-start">953 <div className="flex size-[192px] shrink-0 items-center justify-center self-center rounded-xl border border-border/50 p-4 sm:self-start">
954 <p className="text-center text-[11px] text-muted-foreground/70">954 <p className="text-center text-2xs text-muted-foreground/70">
955 No QR for this endpoint. Another device scanning a loopback link would dial itself;955 No QR for this endpoint. Another device scanning a loopback link would dial itself;
956 copy the URL for use on this machine instead.956 copy the URL for use on this machine instead.
957 </p>957 </p>
...@@ -1011,7 +1011,7 @@ const ConnectedClientListRow = memo(function ConnectedClientListRow({...@@ -1011,7 +1011,7 @@ const ConnectedClientListRow = memo(function ConnectedClientListRow({
1011 />1011 />
1012 <h3 className="text-sm font-medium text-foreground">{primaryLabel}</h3>1012 <h3 className="text-sm font-medium text-foreground">{primaryLabel}</h3>
1013 {clientSession.current ? (1013 {clientSession.current ? (
1014 <span className="text-[10px] text-muted-foreground/80 rounded-md border border-border/50 bg-muted/50 px-1 py-0.5">1014 <span className="text-3xs text-muted-foreground/80 rounded-md border border-border/50 bg-muted/50 px-1 py-0.5">
1015 This device1015 This device
1016 </span>1016 </span>
1017 ) : null}1017 ) : null}
...@@ -1335,14 +1335,14 @@ const AdvertisedEndpointListRow = memo(function AdvertisedEndpointListRow({...@@ -1335,14 +1335,14 @@ const AdvertisedEndpointListRow = memo(function AdvertisedEndpointListRow({
1335 </Tooltip>1335 </Tooltip>
1336 ) : null}1336 ) : null}
1337 {!isAvailable ? (1337 {!isAvailable ? (
1338 <span className="shrink-0 rounded-md border border-border/70 px-1 py-0.5 text-[10px] text-muted-foreground">1338 <span className="shrink-0 rounded-md border border-border/70 px-1 py-0.5 text-3xs text-muted-foreground">
1339 Setup required1339 Setup required
1340 </span>1340 </span>
1341 ) : null}1341 ) : null}
1342 </div>1342 </div>
1343 <div className="ml-auto flex min-h-6 shrink-0 items-center justify-end gap-2">1343 <div className="ml-auto flex min-h-6 shrink-0 items-center justify-end gap-2">
1344 {isDefault ? (1344 {isDefault ? (
1345 <span className="rounded-md border border-primary/30 bg-primary/10 px-1 py-0.5 text-[10px] text-primary">1345 <span className="rounded-md border border-primary/30 bg-primary/10 px-1 py-0.5 text-3xs text-primary">
1346 Default1346 Default
1347 </span>1347 </span>
1348 ) : null}1348 ) : null}
...@@ -2660,7 +2660,7 @@ export function ConnectionsSettings() {...@@ -2660,7 +2660,7 @@ export function ConnectionsSettings() {
2660 </label>2660 </label>
2661 </div>2661 </div>
2662 <div>2662 <div>
2663 <span className="mt-1 block text-[11px] text-muted-foreground">2663 <span className="mt-1 block text-2xs text-muted-foreground">
2664 Paste a full pairing URL here to fill both fields automatically.2664 Paste a full pairing URL here to fill both fields automatically.
2665 </span>2665 </span>
2666 </div>2666 </div>
apps/web/src/components/settings/CustomModelEditor.tsx+2-2
...@@ -169,7 +169,7 @@ export function CustomModelEditor({...@@ -169,7 +169,7 @@ export function CustomModelEditor({
169 className="min-w-0 flex-1"169 className="min-w-0 flex-1"
170 aria-label="Choice label"170 aria-label="Choice label"
171 />171 />
172 <label className="flex shrink-0 items-center gap-1.5 text-[11px] text-muted-foreground">172 <label className="flex shrink-0 items-center gap-1.5 text-2xs text-muted-foreground">
173 <Switch173 <Switch
174 size="sm"174 size="sm"
175 checked={choice.isDefault}175 checked={choice.isDefault}
...@@ -201,7 +201,7 @@ export function CustomModelEditor({...@@ -201,7 +201,7 @@ export function CustomModelEditor({
201 className="flex flex-col gap-2 rounded-md border border-border/60 bg-background/40 p-2.5"201 className="flex flex-col gap-2 rounded-md border border-border/60 bg-background/40 p-2.5"
202 >202 >
203 <div className="flex flex-wrap items-center gap-2">203 <div className="flex flex-wrap items-center gap-2">
204 <span className="w-14 shrink-0 text-[11px] text-muted-foreground">Option {index + 1}</span>204 <span className="w-14 shrink-0 text-2xs text-muted-foreground">Option {index + 1}</span>
205 {presets.length > 0 ? (205 {presets.length > 0 ? (
206 <Select206 <Select
207 value={idSelectValue(descriptor)}207 value={idSelectValue(descriptor)}
apps/web/src/components/settings/DiagnosticsSettings.tsx+10-10
...@@ -94,7 +94,7 @@ function StatBlock({...@@ -94,7 +94,7 @@ function StatBlock({
94}) {94}) {
95 return (95 return (
96 <div className="min-w-0 border-border/60 px-4 py-3 sm:px-5">96 <div className="min-w-0 border-border/60 px-4 py-3 sm:px-5">
97 <div className="flex min-w-0 items-center gap-1.5 text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground/70">97 <div className="flex min-w-0 items-center gap-1.5 text-2xs font-medium uppercase tracking-widest text-muted-foreground/70">
98 <span className="min-w-0 truncate">{label}</span>98 <span className="min-w-0 truncate">{label}</span>
99 {tooltip ? (99 {tooltip ? (
100 <Tooltip>100 <Tooltip>
...@@ -183,7 +183,7 @@ function DiagnosticsTable({...@@ -183,7 +183,7 @@ function DiagnosticsTable({
183 ))}183 ))}
184 </colgroup>184 </colgroup>
185 ) : null}185 ) : null}
186 <thead className="border-b border-border/60 text-[11px] uppercase tracking-[0.08em] text-muted-foreground/70">186 <thead className="border-b border-border/60 text-2xs uppercase tracking-widest text-muted-foreground/70">
187 <tr>187 <tr>
188 {headers.map((header, index) => (188 {headers.map((header, index) => (
189 <th189 <th
...@@ -215,7 +215,7 @@ function TraceIdCell({ traceId }: { traceId: string }) {...@@ -215,7 +215,7 @@ function TraceIdCell({ traceId }: { traceId: string }) {
215 <Tooltip>215 <Tooltip>
216 <TooltipTrigger216 <TooltipTrigger
217 render={217 render={
218 <span className="min-w-0 flex-1 truncate font-mono text-[11px]">218 <span className="min-w-0 flex-1 truncate font-mono text-2xs">
219 {shortenTraceId(traceId)}219 {shortenTraceId(traceId)}
220 </span>220 </span>
221 }221 }
...@@ -362,7 +362,7 @@ function ProcessDiagnosticsTable({...@@ -362,7 +362,7 @@ function ProcessDiagnosticsTable({
362 <col className="w-[11%]" />362 <col className="w-[11%]" />
363 <col className="w-[6%]" />363 <col className="w-[6%]" />
364 </colgroup>364 </colgroup>
365 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-[11px] uppercase tracking-[0.08em] text-muted-foreground/70">365 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-2xs uppercase tracking-widest text-muted-foreground/70">
366 <tr>366 <tr>
367 <th className="px-4 py-2 font-semibold sm:pl-5">Name</th>367 <th className="px-4 py-2 font-semibold sm:pl-5">Name</th>
368 <th className="px-3 py-2 text-right font-semibold">CPU</th>368 <th className="px-3 py-2 text-right font-semibold">CPU</th>
...@@ -588,7 +588,7 @@ function ProcessResourceHistoryTable({...@@ -588,7 +588,7 @@ function ProcessResourceHistoryTable({
588 <col className="w-[16%]" />588 <col className="w-[16%]" />
589 <col className="w-[10%]" />589 <col className="w-[10%]" />
590 </colgroup>590 </colgroup>
591 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-[11px] uppercase tracking-[0.08em] text-muted-foreground/70">591 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-2xs uppercase tracking-widest text-muted-foreground/70">
592 <tr>592 <tr>
593 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>593 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>
594 <th className="px-3 py-2 text-right font-semibold">CPU Time</th>594 <th className="px-3 py-2 text-right font-semibold">CPU Time</th>
...@@ -662,15 +662,15 @@ function DiagnosticsLastChecked({ checkedAt }: { checkedAt: DateTime.Utc | null...@@ -662,15 +662,15 @@ function DiagnosticsLastChecked({ checkedAt }: { checkedAt: DateTime.Utc | null
662 const relative = getRelativeTimeState(checkedAt ? DateTime.formatIso(checkedAt) : null);662 const relative = getRelativeTimeState(checkedAt ? DateTime.formatIso(checkedAt) : null);
663663
664 if (relative.status === "missing") {664 if (relative.status === "missing") {
665 return <span className="text-[11px] text-muted-foreground/50">Checking</span>;665 return <span className="text-2xs text-muted-foreground/50">Checking</span>;
666 }666 }
667667
668 if (relative.status === "invalid") {668 if (relative.status === "invalid") {
669 return <span className="text-[11px] text-muted-foreground/50">Checked unavailable</span>;669 return <span className="text-2xs text-muted-foreground/50">Checked unavailable</span>;
670 }670 }
671671
672 return (672 return (
673 <span className="text-[11px] text-muted-foreground/60">673 <span className="text-2xs text-muted-foreground/60">
674 {relative.suffix ? (674 {relative.suffix ? (
675 <>675 <>
676 Checked <span className="font-mono tabular-nums">{relative.value}</span> {relative.suffix}676 Checked <span className="font-mono tabular-nums">{relative.value}</span> {relative.suffix}
...@@ -1222,7 +1222,7 @@ export function DiagnosticsSettingsPanel() {...@@ -1222,7 +1222,7 @@ export function DiagnosticsSettingsPanel() {
1222 <col className="w-[26%]" />1222 <col className="w-[26%]" />
1223 <col className="w-[30%]" />1223 <col className="w-[30%]" />
1224 </colgroup>1224 </colgroup>
1225 <thead className="border-b border-border/60 text-[11px] uppercase tracking-[0.08em] text-muted-foreground/70">1225 <thead className="border-b border-border/60 text-2xs uppercase tracking-widest text-muted-foreground/70">
1226 <tr>1226 <tr>
1227 <th className="whitespace-nowrap px-4 py-2.5 font-semibold sm:pl-5">Time</th>1227 <th className="whitespace-nowrap px-4 py-2.5 font-semibold sm:pl-5">Time</th>
1228 <th className="whitespace-nowrap px-4 py-2.5 font-semibold">Level</th>1228 <th className="whitespace-nowrap px-4 py-2.5 font-semibold">Level</th>
...@@ -1241,7 +1241,7 @@ export function DiagnosticsSettingsPanel() {...@@ -1241,7 +1241,7 @@ export function DiagnosticsSettingsPanel() {
1241 {formatRelativeNoWrap(event.seenAt)}1241 {formatRelativeNoWrap(event.seenAt)}
1242 </td>1242 </td>
1243 <td className="px-4 py-3 align-top">1243 <td className="px-4 py-3 align-top">
1244 <span className="inline-flex rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] font-medium uppercase text-foreground/80">1244 <span className="inline-flex rounded bg-muted px-1.5 py-0.5 font-mono text-2xs font-medium uppercase text-foreground/80">
1245 {event.level}1245 {event.level}
1246 </span>1246 </span>
1247 </td>1247 </td>
apps/web/src/components/settings/FontFamilyPicker.tsx+1-3
...@@ -173,9 +173,7 @@ export function FontFamilyPicker({...@@ -173,9 +173,7 @@ export function FontFamilyPicker({
173 {family}173 {family}
174 </span>174 </span>
175 <span className="flex shrink-0 items-center gap-1.5">175 <span className="flex shrink-0 items-center gap-1.5">
176 {isDefault ? (176 {isDefault ? <span className="text-3xs text-muted-foreground/60">default</span> : null}
177 <span className="text-[10px] text-muted-foreground/60">default</span>
178 ) : null}
179 {item === selectedValue ? (177 {item === selectedValue ? (
180 <CheckIcon className="size-3.5 text-muted-foreground" />178 <CheckIcon className="size-3.5 text-muted-foreground" />
181 ) : null}179 ) : null}
apps/web/src/components/settings/KeybindingsSettings.tsx+8-8
...@@ -255,7 +255,7 @@ function WarningTooltipIcon({...@@ -255,7 +255,7 @@ function WarningTooltipIcon({
255 tabIndex={focusable ? 0 : undefined}255 tabIndex={focusable ? 0 : undefined}
256 aria-label={label}256 aria-label={label}
257 className={cn(257 className={cn(
258 "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-warning outline-none transition-colors hover:bg-warning/10 focus-visible:ring-[3px] focus-visible:ring-warning/25",258 "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-warning outline-none transition-colors hover:bg-warning/10 focus-visible:ring-3 focus-visible:ring-warning/25",
259 className,259 className,
260 )}260 )}
261 />261 />
...@@ -668,7 +668,7 @@ function WhenExpressionBuilder({...@@ -668,7 +668,7 @@ function WhenExpressionBuilder({
668 ) : null}668 ) : null}
669 </InputGroup>669 </InputGroup>
670 {parseError ? (670 {parseError ? (
671 <div className="flex items-center gap-1.5 text-[11px] text-destructive">671 <div className="flex items-center gap-1.5 text-2xs text-destructive">
672 <CircleXIcon className="size-3.5" />672 <CircleXIcon className="size-3.5" />
673 {parseError}673 {parseError}
674 </div>674 </div>
...@@ -698,7 +698,7 @@ function WhenExpressionBuilder({...@@ -698,7 +698,7 @@ function WhenExpressionBuilder({
698 </div>698 </div>
699 )}699 )}
700 {parseError ? (700 {parseError ? (
701 <div className="pointer-events-none absolute inset-0 flex items-center justify-center rounded-lg border border-destructive/30 bg-background/75 p-4 text-center text-xs text-destructive backdrop-blur-[1px]">701 <div className="pointer-events-none absolute inset-0 flex items-center justify-center rounded-lg border border-destructive/30 bg-background/75 p-4 text-center text-xs text-destructive backdrop-blur-xs">
702 Fix the expression above to continue editing visually.702 Fix the expression above to continue editing visually.
703 </div>703 </div>
704 ) : null}704 ) : null}
...@@ -842,7 +842,7 @@ function KeybindingKeyControl({...@@ -842,7 +842,7 @@ function KeybindingKeyControl({
842 onClick={() => setDraft({ isRecording: true })}842 onClick={() => setDraft({ isRecording: true })}
843 aria-label={`Edit shortcut for ${commandLabel(row.command)}: ${formatShortcutLabel(row.binding.shortcut)}`}843 aria-label={`Edit shortcut for ${commandLabel(row.command)}: ${formatShortcutLabel(row.binding.shortcut)}`}
844 className={cn(844 className={cn(
845 "inline-flex h-8 cursor-pointer items-center rounded-md border border-transparent px-1.5 sm:h-7 outline-none transition-colors hover:border-border/70 hover:bg-accent focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/24",845 "inline-flex h-8 cursor-pointer items-center rounded-md border border-transparent px-1.5 sm:h-7 outline-none transition-colors hover:border-border/70 hover:bg-accent focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/24",
846 pillClassName,846 pillClassName,
847 )}847 )}
848 >848 >
...@@ -989,7 +989,7 @@ function KeybindingRowWhen({...@@ -989,7 +989,7 @@ function KeybindingRowWhen({
989}) {989}) {
990 return (990 return (
991 <span className="flex h-6 items-center gap-1.5">991 <span className="flex h-6 items-center gap-1.5">
992 <span className="text-[12px] leading-none text-muted-foreground/70">When</span>992 <span className="text-xs leading-none text-muted-foreground/70">When</span>
993 <WhenClauseControl993 <WhenClauseControl
994 label={commandLabel(row.command)}994 label={commandLabel(row.command)}
995 expression={editor.whenDraftExpression}995 expression={editor.whenDraftExpression}
...@@ -1234,7 +1234,7 @@ function NewKeybindingSettingsRow(props: NewKeybindingProps) {...@@ -1234,7 +1234,7 @@ function NewKeybindingSettingsRow(props: NewKeybindingProps) {
1234 title="New keybinding"1234 title="New keybinding"
1235 description={1235 description={
1236 <span className="flex h-6 items-center gap-1.5">1236 <span className="flex h-6 items-center gap-1.5">
1237 <span className="text-[12px] leading-none text-muted-foreground/70">When</span>1237 <span className="text-xs leading-none text-muted-foreground/70">When</span>
1238 <NewKeybindingWhen draft={draft} variables={variables} />1238 <NewKeybindingWhen draft={draft} variables={variables} />
1239 </span>1239 </span>
1240 }1240 }
...@@ -1312,7 +1312,7 @@ function KeybindingsList(props: KeybindingsListProps) {...@@ -1312,7 +1312,7 @@ function KeybindingsList(props: KeybindingsListProps) {
1312/** Shown in the browser build only; the desktop app receives every shortcut. */1312/** Shown in the browser build only; the desktop app receives every shortcut. */
1313function BrowserKeybindingNotice() {1313function BrowserKeybindingNotice() {
1314 return (1314 return (
1315 <div className="flex items-center gap-2 px-3 py-2.5 text-[12px] leading-[1.45] text-muted-foreground sm:px-4">1315 <div className="flex items-center gap-2 px-3 py-2.5 text-xs leading-normal text-muted-foreground sm:px-4">
1316 <TriangleAlertIcon className="size-3.5 shrink-0 text-warning" aria-hidden />1316 <TriangleAlertIcon className="size-3.5 shrink-0 text-warning" aria-hidden />
1317 <span>1317 <span>
1318 Some shortcuts may be claimed by the browser before T3 Code sees them. Use the desktop app1318 Some shortcuts may be claimed by the browser before T3 Code sees them. Use the desktop app
...@@ -1488,7 +1488,7 @@ export function KeybindingsSettingsPanel() {...@@ -1488,7 +1488,7 @@ export function KeybindingsSettingsPanel() {
1488 const cancelAdd = useCallback(() => setIsAddingBinding(false), []);1488 const cancelAdd = useCallback(() => setIsAddingBinding(false), []);
14891489
1490 const bindingsCount = (1490 const bindingsCount = (
1491 <span className="text-[11px] text-muted-foreground">1491 <span className="text-2xs text-muted-foreground">
1492 {rows.length + (isAddingBinding ? 1 : 0)}{" "}1492 {rows.length + (isAddingBinding ? 1 : 0)}{" "}
1493 {rows.length + (isAddingBinding ? 1 : 0) === 1 ? "binding" : "bindings"}1493 {rows.length + (isAddingBinding ? 1 : 0) === 1 ? "binding" : "bindings"}
1494 </span>1494 </span>
apps/web/src/components/settings/OpenSourceLicenses.tsx+1-1
...@@ -179,7 +179,7 @@ function LicenseManifestError({ message, onRetry }: { message: string; onRetry:...@@ -179,7 +179,7 @@ function LicenseManifestError({ message, onRetry }: { message: string; onRetry:
179 <div className="flex flex-col items-start gap-3 px-3 py-5 sm:px-4">179 <div className="flex flex-col items-start gap-3 px-3 py-5 sm:px-4">
180 <div className="flex flex-col gap-1">180 <div className="flex flex-col gap-1">
181 <h3 className="text-sm font-medium text-foreground">Open-source notices are unavailable</h3>181 <h3 className="text-sm font-medium text-foreground">Open-source notices are unavailable</h3>
182 <p className="max-w-[70ch] text-pretty text-[13px] leading-[1.45] text-muted-foreground/80">182 <p className="max-w-[70ch] text-pretty text-xs leading-normal text-muted-foreground/80">
183 {message}183 {message}
184 </p>184 </p>
185 </div>185 </div>
apps/web/src/components/settings/PanelAnimationsPreview.tsx+1-1
...@@ -5,7 +5,7 @@ import { cn } from "~/lib/utils";...@@ -5,7 +5,7 @@ import { cn } from "~/lib/utils";
5export function PanelAnimationsPreview({ durationMs }: { durationMs: number }) {5export function PanelAnimationsPreview({ durationMs }: { durationMs: number }) {
6 const [panelsOpen, setPanelsOpen] = useState(true);6 const [panelsOpen, setPanelsOpen] = useState(true);
7 const transitionClass =7 const transitionClass =
8 "transition-[width,height,border-width] [transition-duration:var(--preview-duration)] ease-out motion-reduce:transition-none";8 "transition-[width,height,border-width] duration-(--preview-duration) ease-out motion-reduce:transition-none";
99
10 return (10 return (
11 <button11 <button
apps/web/src/components/settings/ProjectActionsList.tsx+2-2
...@@ -34,12 +34,12 @@ export function ProjectActionsList({...@@ -34,12 +34,12 @@ export function ProjectActionsList({
34 <ScriptIcon icon={script.icon} className="size-4 shrink-0 text-muted-foreground" />34 <ScriptIcon icon={script.icon} className="size-4 shrink-0 text-muted-foreground" />
35 <span className="min-w-0 truncate">{script.name}</span>35 <span className="min-w-0 truncate">{script.name}</span>
36 {script.runOnWorktreeCreate ? (36 {script.runOnWorktreeCreate ? (
37 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-[11px] font-normal text-muted-foreground">37 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-2xs font-normal text-muted-foreground">
38 setup38 setup
39 </span>39 </span>
40 ) : null}40 ) : null}
41 {script.previewUrl ? (41 {script.previewUrl ? (
42 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-[11px] font-normal text-muted-foreground max-sm:hidden">42 <span className="shrink-0 rounded-sm border border-border/60 px-1.5 py-px text-2xs font-normal text-muted-foreground max-sm:hidden">
43 preview · desktop only43 preview · desktop only
44 </span>44 </span>
45 ) : null}45 ) : null}
apps/web/src/components/settings/ProviderInstanceCard.test.ts+1-1
...@@ -118,7 +118,7 @@ describe("deriveProviderModelsForDisplay", () => {...@@ -118,7 +118,7 @@ describe("deriveProviderModelsForDisplay", () => {
118118
119 expect(markup).toContain("Authenticated as");119 expect(markup).toContain("Authenticated as");
120 expect(markup).toContain('aria-label="Toggle account email visibility"');120 expect(markup).toContain('aria-label="Toggle account email visibility"');
121 expect(markup).toContain("blur-[2px]");121 expect(markup).toContain("blur-xs");
122 expect(markup).not.toContain("developer@example.com");122 expect(markup).not.toContain("developer@example.com");
123 });123 });
124 it("surfaces a failed probe message in both the list row and the editor", () => {124 it("surfaces a failed probe message in both the list row and the editor", () => {
apps/web/src/components/settings/ProviderInstanceCard.tsx+7-7
...@@ -570,7 +570,7 @@ export function ProviderInstanceCard({...@@ -570,7 +570,7 @@ export function ProviderInstanceCard({
570 showBadge={Boolean(accentColor)}570 showBadge={Boolean(accentColor)}
571 className="size-5"571 className="size-5"
572 iconClassName="size-4 text-foreground/80"572 iconClassName="size-4 text-foreground/80"
573 badgeClassName="right-[-0.125rem] bottom-[-0.125rem] h-3 min-w-3 px-0.5 text-[7px]"573 badgeClassName="right-[-0.125rem] bottom-[-0.125rem] h-3 min-w-3 px-0.5 text-3xs"
574 />574 />
575 ) : FallbackIconComponent ? (575 ) : FallbackIconComponent ? (
576 <span className="inline-flex size-5 shrink-0 items-center justify-center">576 <span className="inline-flex size-5 shrink-0 items-center justify-center">
...@@ -578,7 +578,7 @@ export function ProviderInstanceCard({...@@ -578,7 +578,7 @@ export function ProviderInstanceCard({
578 </span>578 </span>
579 ) : (579 ) : (
580 <span580 <span
581 className="inline-flex size-5 shrink-0 items-center justify-center text-[10px] font-semibold leading-none text-foreground/80"581 className="inline-flex size-5 shrink-0 items-center justify-center text-3xs font-semibold leading-none text-foreground/80"
582 aria-hidden582 aria-hidden
583 >583 >
584 {providerInstanceInitials(displayName)}584 {providerInstanceInitials(displayName)}
...@@ -655,7 +655,7 @@ export function ProviderInstanceCard({...@@ -655,7 +655,7 @@ export function ProviderInstanceCard({
655 <span className="flex min-w-0 items-center gap-2">655 <span className="flex min-w-0 items-center gap-2">
656 <span className="truncate text-sm font-medium text-foreground">{displayName}</span>656 <span className="truncate text-sm font-medium text-foreground">{displayName}</span>
657 {String(instanceId) !== String(instance.driver) ? (657 {String(instanceId) !== String(instance.driver) ? (
658 <code className="min-w-0 truncate rounded bg-muted/60 px-1 py-0.5 text-[10px] text-muted-foreground">658 <code className="min-w-0 truncate rounded bg-muted/60 px-1 py-0.5 text-3xs text-muted-foreground">
659 {instanceId}659 {instanceId}
660 </code>660 </code>
661 ) : null}661 ) : null}
...@@ -708,7 +708,7 @@ export function ProviderInstanceCard({...@@ -708,7 +708,7 @@ export function ProviderInstanceCard({
708 )708 )
709 ) : null}709 ) : null}
710 </span>710 </span>
711 <span className="mt-0.5 flex items-start gap-1.5 text-[13px] leading-[1.45] text-muted-foreground/80">711 <span className="mt-0.5 flex items-start gap-1.5 text-xs leading-normal text-muted-foreground/80">
712 {statusDotNode ? (712 {statusDotNode ? (
713 <span className="flex h-[1.45em] shrink-0 items-center">{statusDotNode}</span>713 <span className="flex h-[1.45em] shrink-0 items-center">{statusDotNode}</span>
714 ) : null}714 ) : null}
...@@ -775,7 +775,7 @@ export function ProviderInstanceCard({...@@ -775,7 +775,7 @@ export function ProviderInstanceCard({
775 <PopoverPopup side="bottom" align="end" width="md">775 <PopoverPopup side="bottom" align="end" width="md">
776 <div className="grid min-w-0 gap-3">776 <div className="grid min-w-0 gap-3">
777 <div className="grid gap-0.5">777 <div className="grid gap-0.5">
778 <p className="text-[13px] font-semibold leading-tight text-foreground">778 <p className="text-sm font-semibold leading-tight text-foreground">
779 {versionAdvisory.title}779 {versionAdvisory.title}
780 </p>780 </p>
781 <p781 <p
...@@ -807,7 +807,7 @@ export function ProviderInstanceCard({...@@ -807,7 +807,7 @@ export function ProviderInstanceCard({
807 </Button>807 </Button>
808 ) : null}808 ) : null}
809 {onRunVersionAction && updateCommand ? (809 {onRunVersionAction && updateCommand ? (
810 <div className="flex items-center gap-2 text-[10px] font-medium uppercase tracking-wider text-muted-foreground">810 <div className="flex items-center gap-2 text-3xs font-medium uppercase tracking-wider text-muted-foreground">
811 <span aria-hidden className="h-px flex-1 bg-border" />811 <span aria-hidden className="h-px flex-1 bg-border" />
812 or, update manually using812 or, update manually using
813 <span aria-hidden className="h-px flex-1 bg-border" />813 <span aria-hidden className="h-px flex-1 bg-border" />
...@@ -815,7 +815,7 @@ export function ProviderInstanceCard({...@@ -815,7 +815,7 @@ export function ProviderInstanceCard({
815 ) : null}815 ) : null}
816 {updateCommand ? (816 {updateCommand ? (
817 <div className="flex min-w-0 items-center gap-1 rounded-md border border-border/70 bg-muted/40 py-0.5 pr-0.5 pl-2">817 <div className="flex min-w-0 items-center gap-1 rounded-md border border-border/70 bg-muted/40 py-0.5 pr-0.5 pl-2">
818 <code className="min-w-0 flex-1 truncate font-mono text-[11px] text-foreground">818 <code className="min-w-0 flex-1 truncate font-mono text-2xs text-foreground">
819 {updateCommand}819 {updateCommand}
820 </code>820 </code>
821 <Tooltip>821 <Tooltip>
apps/web/src/components/settings/ProviderModelsSection.tsx+4-4
...@@ -470,19 +470,19 @@ export function ProviderModelsSection({...@@ -470,19 +470,19 @@ export function ProviderModelsSection({
470 <span className="flex min-w-0 items-baseline gap-2">470 <span className="flex min-w-0 items-baseline gap-2">
471 <span className={cn(nameClassName, "truncate")}>{model.name}</span>471 <span className={cn(nameClassName, "truncate")}>{model.name}</span>
472 {model.name !== model.slug ? (472 {model.name !== model.slug ? (
473 <code className="truncate font-mono text-[11px] text-muted-foreground/70">473 <code className="truncate font-mono text-2xs text-muted-foreground/70">
474 {model.slug}474 {model.slug}
475 </code>475 </code>
476 ) : null}476 ) : null}
477 {model.isCustom ? (477 {model.isCustom ? (
478 <span className="text-[11px] text-muted-foreground/70">custom</span>478 <span className="text-2xs text-muted-foreground/70">custom</span>
479 ) : null}479 ) : null}
480 </span>480 </span>
481 {/*481 {/*
482 Always a grid item so the columns line up across rows; the text482 Always a grid item so the columns line up across rows; the text
483 itself drops out on phone widths where it would starve the name.483 itself drops out on phone widths where it would starve the name.
484 */}484 */}
485 <span className="text-[11px] text-muted-foreground/70">485 <span className="text-2xs text-muted-foreground/70">
486 {capLabels.length > 0 ? (486 {capLabels.length > 0 ? (
487 <span className="hidden sm:inline">{capLabels.join(" · ")}</span>487 <span className="hidden sm:inline">{capLabels.join(" · ")}</span>
488 ) : null}488 ) : null}
...@@ -494,7 +494,7 @@ export function ProviderModelsSection({...@@ -494,7 +494,7 @@ export function ProviderModelsSection({
494 };494 };
495495
496 const groupLabel = (label: string, isFirst: boolean) => (496 const groupLabel = (label: string, isFirst: boolean) => (
497 <div className={cn("px-2 pb-1.5 text-[11px] text-muted-foreground", isFirst ? "pt-1" : "pt-5")}>497 <div className={cn("px-2 pb-1.5 text-2xs text-muted-foreground", isFirst ? "pt-1" : "pt-5")}>
498 {label}498 {label}
499 </div>499 </div>
500 );500 );
apps/web/src/components/settings/ProviderSettingsForm.tsx+1-1
...@@ -240,7 +240,7 @@ function ProviderSettingsFieldRow({...@@ -240,7 +240,7 @@ function ProviderSettingsFieldRow({
240 const inputId = `${idPrefix}-${field.key}`;240 const inputId = `${idPrefix}-${field.key}`;
241 const descriptionClassName =241 const descriptionClassName =
242 variant === "dialog"242 variant === "dialog"
243 ? "text-[11px] text-muted-foreground"243 ? "text-2xs text-muted-foreground"
244 : "mt-1 block text-xs text-muted-foreground";244 : "mt-1 block text-xs text-muted-foreground";
245 const label = <span className="text-xs font-medium text-foreground">{field.label}</span>;245 const label = <span className="text-xs font-medium text-foreground">{field.label}</span>;
246 const description = field.description ? (246 const description = field.description ? (
apps/web/src/components/settings/RedactedSensitiveText.tsx+2-2
...@@ -44,8 +44,8 @@ export function RedactedSensitiveText(props: {...@@ -44,8 +44,8 @@ export function RedactedSensitiveText(props: {
44 <button44 <button
45 type="button"45 type="button"
46 className={cn(46 className={cn(
47 "min-w-0 cursor-pointer rounded-sm font-mono text-[11px] leading-normal transition hover:text-foreground",47 "min-w-0 cursor-pointer rounded-sm font-mono text-2xs leading-normal transition hover:text-foreground",
48 revealed ? "text-muted-foreground" : "select-none text-muted-foreground blur-[2px]",48 revealed ? "text-muted-foreground" : "select-none text-muted-foreground blur-xs",
49 props.className,49 props.className,
50 )}50 )}
51 onClick={() => setRevealed((current) => !current)}51 onClick={() => setRevealed((current) => !current)}
apps/web/src/components/settings/ResourceTelemetryDiagnostics.tsx+35-35
...@@ -194,7 +194,7 @@ function SourceStatusBadge({...@@ -194,7 +194,7 @@ function SourceStatusBadge({
194 return (194 return (
195 <span195 <span
196 className={cn(196 className={cn(
197 "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.08em]",197 "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-3xs font-semibold uppercase tracking-widest",
198 tone === "neutral" && "border-border/70 bg-muted/45 text-muted-foreground",198 tone === "neutral" && "border-border/70 bg-muted/45 text-muted-foreground",
199 tone === "default" && "border-success/25 bg-success/10 text-success-foreground",199 tone === "default" && "border-success/25 bg-success/10 text-success-foreground",
200 tone === "warning" && "border-warning/30 bg-warning/10 text-warning-foreground",200 tone === "warning" && "border-warning/30 bg-warning/10 text-warning-foreground",
...@@ -218,14 +218,14 @@ function SourceStatusBadge({...@@ -218,14 +218,14 @@ function SourceStatusBadge({
218function LastSampleLabel({ sampledAt }: { sampledAt: DateTime.Utc | null }) {218function LastSampleLabel({ sampledAt }: { sampledAt: DateTime.Utc | null }) {
219 useRelativeTimeTick();219 useRelativeTimeTick();
220 if (!sampledAt) {220 if (!sampledAt) {
221 return <span className="text-[11px] text-muted-foreground/55">Waiting for sample</span>;221 return <span className="text-2xs text-muted-foreground/55">Waiting for sample</span>;
222 }222 }
223 const relative = formatRelativeTime(DateTime.formatIso(sampledAt));223 const relative = formatRelativeTime(DateTime.formatIso(sampledAt));
224 if (!relative) {224 if (!relative) {
225 return <span className="text-[11px] text-muted-foreground/55">Waiting for sample</span>;225 return <span className="text-2xs text-muted-foreground/55">Waiting for sample</span>;
226 }226 }
227 return (227 return (
228 <span className="text-[11px] text-muted-foreground/60">228 <span className="text-2xs text-muted-foreground/60">
229 Updated <span className="font-mono tabular-nums">{relative.value}</span>229 Updated <span className="font-mono tabular-nums">{relative.value}</span>
230 {relative.suffix ? ` ${relative.suffix}` : ""}230 {relative.suffix ? ` ${relative.suffix}` : ""}
231 </span>231 </span>
...@@ -247,7 +247,7 @@ function IconStat({...@@ -247,7 +247,7 @@ function IconStat({
247}) {247}) {
248 return (248 return (
249 <div className="group min-w-0 px-4 py-4 sm:px-5">249 <div className="group min-w-0 px-4 py-4 sm:px-5">
250 <div className="flex items-center gap-2 text-[10px] font-semibold uppercase tracking-[0.11em] text-muted-foreground/70">250 <div className="flex items-center gap-2 text-3xs font-semibold uppercase tracking-widest text-muted-foreground/70">
251 <span className="text-muted-foreground/55 transition-colors group-hover:text-foreground/65">251 <span className="text-muted-foreground/55 transition-colors group-hover:text-foreground/65">
252 {icon}252 {icon}
253 </span>253 </span>
...@@ -255,7 +255,7 @@ function IconStat({...@@ -255,7 +255,7 @@ function IconStat({
255 </div>255 </div>
256 <div256 <div
257 className={cn(257 className={cn(
258 "mt-2.5 truncate font-mono text-2xl font-semibold tracking-[-0.05em] tabular-nums text-foreground",258 "mt-2.5 truncate font-mono text-2xl font-semibold tracking-tighter tabular-nums text-foreground",
259 tone === "warning" && "text-warning-foreground",259 tone === "warning" && "text-warning-foreground",
260 tone === "danger" && "text-destructive",260 tone === "danger" && "text-destructive",
261 )}261 )}
...@@ -263,7 +263,7 @@ function IconStat({...@@ -263,7 +263,7 @@ function IconStat({
263 {value}263 {value}
264 </div>264 </div>
265 {detail ? (265 {detail ? (
266 <div className="mt-1.5 truncate text-[10px] text-muted-foreground/60">{detail}</div>266 <div className="mt-1.5 truncate text-3xs text-muted-foreground/60">{detail}</div>
267 ) : null}267 ) : null}
268 </div>268 </div>
269 );269 );
...@@ -282,10 +282,10 @@ function AggregateCard({...@@ -282,10 +282,10 @@ function AggregateCard({
282 <div className="relative overflow-hidden border-t border-border/60 px-4 py-4 first:border-t-0 md:border-t-0 md:border-l md:first:border-l-0 sm:px-5">282 <div className="relative overflow-hidden border-t border-border/60 px-4 py-4 first:border-t-0 md:border-t-0 md:border-l md:first:border-l-0 sm:px-5">
283 <span className={cn("absolute inset-x-5 top-0 h-0.5 rounded-full opacity-75", accentClass)} />283 <span className={cn("absolute inset-x-5 top-0 h-0.5 rounded-full opacity-75", accentClass)} />
284 <div className="flex items-center justify-between gap-3">284 <div className="flex items-center justify-between gap-3">
285 <div className="text-[10px] font-semibold uppercase tracking-[0.11em] text-muted-foreground/75">285 <div className="text-3xs font-semibold uppercase tracking-widest text-muted-foreground/75">
286 {label}286 {label}
287 </div>287 </div>
288 <div className="rounded-md bg-muted/55 px-1.5 py-0.5 font-mono text-[9px] tabular-nums text-muted-foreground/70">288 <div className="rounded-md bg-muted/55 px-1.5 py-0.5 font-mono text-3xs tabular-nums text-muted-foreground/70">
289 {aggregate.processCount} {aggregate.processCount === 1 ? "process" : "processes"}289 {aggregate.processCount} {aggregate.processCount === 1 ? "process" : "processes"}
290 </div>290 </div>
291 </div>291 </div>
...@@ -302,7 +302,7 @@ function AggregateCard({...@@ -302,7 +302,7 @@ function AggregateCard({
302function MetricPair({ label, value }: { label: string; value: string }) {302function MetricPair({ label, value }: { label: string; value: string }) {
303 return (303 return (
304 <div className="min-w-0">304 <div className="min-w-0">
305 <div className="text-[9px] font-semibold uppercase tracking-[0.08em] text-muted-foreground/45">305 <div className="text-3xs font-semibold uppercase tracking-widest text-muted-foreground/45">
306 {label}306 {label}
307 </div>307 </div>
308 <div className="truncate font-mono text-xs font-medium tabular-nums text-foreground/90">308 <div className="truncate font-mono text-xs font-medium tabular-nums text-foreground/90">
...@@ -319,8 +319,8 @@ function HealthSource({ label, health }: { label: string; health: ResourceTeleme...@@ -319,8 +319,8 @@ function HealthSource({ label, health }: { label: string; health: ResourceTeleme
319 return (319 return (
320 <div className="flex items-start justify-between gap-4 border-t border-border/50 py-3 first:border-t-0">320 <div className="flex items-start justify-between gap-4 border-t border-border/50 py-3 first:border-t-0">
321 <div className="min-w-0">321 <div className="min-w-0">
322 <div className="text-[13px] font-medium text-foreground">{label}</div>322 <div className="text-sm font-medium text-foreground">{label}</div>
323 <div className="mt-1 text-[11px] leading-relaxed text-muted-foreground/65">323 <div className="mt-1 text-2xs leading-relaxed text-muted-foreground/65">
324 {expectedInBrowser324 {expectedInBrowser
325 ? "Available when this page runs inside the desktop app."325 ? "Available when this page runs inside the desktop app."
326 : Option.match(health.lastError, {326 : Option.match(health.lastError, {
...@@ -356,10 +356,10 @@ function DetailRow({...@@ -356,10 +356,10 @@ function DetailRow({
356}) {356}) {
357 return (357 return (
358 <div className="flex items-center justify-between gap-4 border-t border-border/50 py-2.5 first:border-t-0">358 <div className="flex items-center justify-between gap-4 border-t border-border/50 py-2.5 first:border-t-0">
359 <span className="text-[11px] text-muted-foreground/75">{label}</span>359 <span className="text-2xs text-muted-foreground/75">{label}</span>
360 <span360 <span
361 className={cn(361 className={cn(
362 "min-w-0 truncate text-right font-mono text-[11px] tabular-nums text-foreground/85",362 "min-w-0 truncate text-right font-mono text-2xs tabular-nums text-foreground/85",
363 valueClassName,363 valueClassName,
364 )}364 )}
365 >365 >
...@@ -405,7 +405,7 @@ function ResourceHistoryChart({...@@ -405,7 +405,7 @@ function ResourceHistoryChart({
405405
406 return (406 return (
407 <div className="border-t border-border/60 px-4 py-4 sm:px-5">407 <div className="border-t border-border/60 px-4 py-4 sm:px-5">
408 <div className="mb-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-[10px] text-muted-foreground/65">408 <div className="mb-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-3xs text-muted-foreground/65">
409 <span className="inline-flex items-center gap-1.5">409 <span className="inline-flex items-center gap-1.5">
410 <span className="h-1.5 w-3 rounded-full bg-foreground/70" /> CPU average410 <span className="h-1.5 w-3 rounded-full bg-foreground/70" /> CPU average
411 </span>411 </span>
...@@ -529,7 +529,7 @@ function ProcessActions({...@@ -529,7 +529,7 @@ function ProcessActions({
529 onSignal: (process: ResourceTelemetryProcess, signal: ServerProcessSignal) => void;529 onSignal: (process: ResourceTelemetryProcess, signal: ServerProcessSignal) => void;
530}) {530}) {
531 if (!canSignalProcess(process)) {531 if (!canSignalProcess(process)) {
532 return <span className="text-[10px] text-muted-foreground/35">—</span>;532 return <span className="text-3xs text-muted-foreground/35">—</span>;
533 }533 }
534 const isSignaling = signalingKeys.has(processIdentityKey(process));534 const isSignaling = signalingKeys.has(processIdentityKey(process));
535 return (535 return (
...@@ -586,7 +586,7 @@ function ProcessTable({...@@ -586,7 +586,7 @@ function ProcessTable({
586 <col className="w-[6%]" />586 <col className="w-[6%]" />
587 <col className="w-[4%]" />587 <col className="w-[4%]" />
588 </colgroup>588 </colgroup>
589 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-[10px] uppercase tracking-[0.08em] text-muted-foreground/65">589 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-3xs uppercase tracking-widest text-muted-foreground/65">
590 <tr>590 <tr>
591 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>591 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>
592 <th className="px-3 py-2 font-semibold">Category</th>592 <th className="px-3 py-2 font-semibold">Category</th>
...@@ -618,7 +618,7 @@ function ProcessTable({...@@ -618,7 +618,7 @@ function ProcessTable({
618 onToggle={toggle}618 onToggle={toggle}
619 />619 />
620 </td>620 </td>
621 <td className="truncate px-3 py-2 text-[11px] text-muted-foreground">621 <td className="truncate px-3 py-2 text-2xs text-muted-foreground">
622 {categoryLabel(process.category)}622 {categoryLabel(process.category)}
623 </td>623 </td>
624 <td className="px-3 py-2 text-right font-mono tabular-nums">624 <td className="px-3 py-2 text-right font-mono tabular-nums">
...@@ -689,7 +689,7 @@ function HistoryProcessTable({...@@ -689,7 +689,7 @@ function HistoryProcessTable({
689 <col className="w-[7%]" />689 <col className="w-[7%]" />
690 <col className="w-[5%]" />690 <col className="w-[5%]" />
691 </colgroup>691 </colgroup>
692 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-[10px] uppercase tracking-[0.08em] text-muted-foreground/65">692 <thead className="sticky top-0 z-10 border-b border-border/60 bg-card text-3xs uppercase tracking-widest text-muted-foreground/65">
693 <tr>693 <tr>
694 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>694 <th className="px-4 py-2 font-semibold sm:pl-5">Process</th>
695 <th className="px-3 py-2 font-semibold">Category</th>695 <th className="px-3 py-2 font-semibold">Category</th>
...@@ -726,7 +726,7 @@ function HistoryProcessTable({...@@ -726,7 +726,7 @@ function HistoryProcessTable({
726 </TooltipPopup>726 </TooltipPopup>
727 </Tooltip>727 </Tooltip>
728 </td>728 </td>
729 <td className="truncate px-3 py-2 text-[11px] text-muted-foreground">729 <td className="truncate px-3 py-2 text-2xs text-muted-foreground">
730 {categoryLabel(process.category)}730 {categoryLabel(process.category)}
731 </td>731 </td>
732 <td className="px-3 py-2 text-right font-mono tabular-nums">732 <td className="px-3 py-2 text-right font-mono tabular-nums">
...@@ -771,7 +771,7 @@ function AttributionTable({ entries }: { entries: ReadonlyArray<ResourceAttribut...@@ -771,7 +771,7 @@ function AttributionTable({ entries }: { entries: ReadonlyArray<ResourceAttribut
771 <col className="w-[10%]" />771 <col className="w-[10%]" />
772 <col className="w-[12%]" />772 <col className="w-[12%]" />
773 </colgroup>773 </colgroup>
774 <thead className="border-b border-border/60 text-[10px] uppercase tracking-[0.08em] text-muted-foreground/65">774 <thead className="border-b border-border/60 text-3xs uppercase tracking-widest text-muted-foreground/65">
775 <tr>775 <tr>
776 <th className="px-4 py-2 font-semibold sm:pl-5">Component</th>776 <th className="px-4 py-2 font-semibold sm:pl-5">Component</th>
777 <th className="px-3 py-2 font-semibold">Operation</th>777 <th className="px-3 py-2 font-semibold">Operation</th>
...@@ -983,10 +983,10 @@ export function ResourceTelemetryDiagnostics({...@@ -983,10 +983,10 @@ export function ResourceTelemetryDiagnostics({
983 </div>983 </div>
984 }984 }
985 >985 >
986 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-[0_1px_1px_rgb(0_0_0/0.03),0_8px_30px_rgb(0_0_0/0.035)]">986 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-sm/5">
987 <div className="flex flex-col gap-3 border-b border-border/60 bg-linear-to-r from-muted/45 via-muted/20 to-transparent px-4 py-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">987 <div className="flex flex-col gap-3 border-b border-border/60 bg-linear-to-r from-muted/45 via-muted/20 to-transparent px-4 py-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">
988 <div>988 <div>
989 <div className="text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/70">989 <div className="text-3xs font-semibold uppercase tracking-widest text-muted-foreground/70">
990 T3 system footprint990 T3 system footprint
991 </div>991 </div>
992 <p className="mt-1 max-w-xl text-xs leading-relaxed text-muted-foreground">992 <p className="mt-1 max-w-xl text-xs leading-relaxed text-muted-foreground">
...@@ -994,7 +994,7 @@ export function ResourceTelemetryDiagnostics({...@@ -994,7 +994,7 @@ export function ResourceTelemetryDiagnostics({
994 the monitor itself.994 the monitor itself.
995 </p>995 </p>
996 </div>996 </div>
997 <div className="flex items-center gap-2 text-[10px] text-muted-foreground/65">997 <div className="flex items-center gap-2 text-3xs text-muted-foreground/65">
998 <span className="size-1.5 rounded-full bg-success" />998 <span className="size-1.5 rounded-full bg-success" />
999 Sampling every {snapshot ? formatSampleInterval(snapshot.sampleIntervalMs) : "..."}999 Sampling every {snapshot ? formatSampleInterval(snapshot.sampleIntervalMs) : "..."}
1000 </div>1000 </div>
...@@ -1091,9 +1091,9 @@ export function ResourceTelemetryDiagnostics({...@@ -1091,9 +1091,9 @@ export function ResourceTelemetryDiagnostics({
1091 ) : null1091 ) : null
1092 }1092 }
1093 >1093 >
1094 <div className="grid overflow-hidden rounded-2xl border border-border/70 bg-card shadow-[0_1px_1px_rgb(0_0_0/0.03)] md:grid-cols-2 md:divide-x md:divide-border/60">1094 <div className="grid overflow-hidden rounded-2xl border border-border/70 bg-card shadow-xs/5 md:grid-cols-2 md:divide-x md:divide-border/60">
1095 <div className="px-4 py-4 sm:px-5">1095 <div className="px-4 py-4 sm:px-5">
1096 <div className="mb-3 flex items-center gap-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/70">1096 <div className="mb-3 flex items-center gap-2 text-3xs font-semibold uppercase tracking-widest text-muted-foreground/70">
1097 <span className="flex size-6 items-center justify-center rounded-md bg-muted/60">1097 <span className="flex size-6 items-center justify-center rounded-md bg-muted/60">
1098 <BatteryIcon className="size-3.5" />1098 <BatteryIcon className="size-3.5" />
1099 </span>1099 </span>
...@@ -1150,10 +1150,10 @@ export function ResourceTelemetryDiagnostics({...@@ -1150,10 +1150,10 @@ export function ResourceTelemetryDiagnostics({
1150 </>1150 </>
1151 ) : (1151 ) : (
1152 <div className="rounded-xl border border-dashed border-border/70 bg-muted/20 px-4 py-5">1152 <div className="rounded-xl border border-dashed border-border/70 bg-muted/20 px-4 py-5">
1153 <div className="text-[13px] font-medium text-foreground">1153 <div className="text-sm font-medium text-foreground">
1154 Desktop host signals not connected1154 Desktop host signals not connected
1155 </div>1155 </div>
1156 <p className="mt-1.5 max-w-sm text-[11px] leading-relaxed text-muted-foreground/70">1156 <p className="mt-1.5 max-w-sm text-2xs leading-relaxed text-muted-foreground/70">
1157 Power, idle, lock, and thermal state are supplied by the desktop host. Process1157 Power, idle, lock, and thermal state are supplied by the desktop host. Process
1158 telemetry remains fully active in this browser session.1158 telemetry remains fully active in this browser session.
1159 </p>1159 </p>
...@@ -1161,7 +1161,7 @@ export function ResourceTelemetryDiagnostics({...@@ -1161,7 +1161,7 @@ export function ResourceTelemetryDiagnostics({
1161 )}1161 )}
1162 </div>1162 </div>
1163 <div className="border-t border-border/60 px-4 py-4 md:border-t-0 sm:px-5">1163 <div className="border-t border-border/60 px-4 py-4 md:border-t-0 sm:px-5">
1164 <div className="mb-3 flex items-center gap-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/70">1164 <div className="mb-3 flex items-center gap-2 text-3xs font-semibold uppercase tracking-widest text-muted-foreground/70">
1165 <span className="flex size-6 items-center justify-center rounded-md bg-muted/60">1165 <span className="flex size-6 items-center justify-center rounded-md bg-muted/60">
1166 <GaugeIcon className="size-3.5" />1166 <GaugeIcon className="size-3.5" />
1167 </span>1167 </span>
...@@ -1228,7 +1228,7 @@ export function ResourceTelemetryDiagnostics({...@@ -1228,7 +1228,7 @@ export function ResourceTelemetryDiagnostics({
1228 </div>1228 </div>
1229 }1229 }
1230 >1230 >
1231 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-[0_1px_1px_rgb(0_0_0/0.03)]">1231 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-xs/5">
1232 {history.error ? (1232 {history.error ? (
1233 <div className="flex items-start gap-2 border-b border-destructive/20 bg-destructive/5 px-4 py-3 text-xs text-destructive sm:px-5">1233 <div className="flex items-start gap-2 border-b border-destructive/20 bg-destructive/5 px-4 py-3 text-xs text-destructive sm:px-5">
1234 <AlertTriangleIcon className="mt-0.5 size-3.5 shrink-0" />1234 <AlertTriangleIcon className="mt-0.5 size-3.5 shrink-0" />
...@@ -1245,13 +1245,13 @@ export function ResourceTelemetryDiagnostics({...@@ -1245,13 +1245,13 @@ export function ResourceTelemetryDiagnostics({
1245 icon={<CpuIcon className="size-4 text-muted-foreground" />}1245 icon={<CpuIcon className="size-4 text-muted-foreground" />}
1246 headerAction={1246 headerAction={
1247 snapshot ? (1247 snapshot ? (
1248 <span className="text-[10px] text-muted-foreground/55">1248 <span className="text-3xs text-muted-foreground/55">
1249 Identity: <span className="font-mono">PID + start time</span>1249 Identity: <span className="font-mono">PID + start time</span>
1250 </span>1250 </span>
1251 ) : null1251 ) : null
1252 }1252 }
1253 >1253 >
1254 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-[0_1px_1px_rgb(0_0_0/0.03)]">1254 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-xs/5">
1255 <ProcessTable1255 <ProcessTable
1256 processes={snapshot?.processes ?? []}1256 processes={snapshot?.processes ?? []}
1257 signalingKeys={signalingKeys}1257 signalingKeys={signalingKeys}
...@@ -1264,11 +1264,11 @@ export function ResourceTelemetryDiagnostics({...@@ -1264,11 +1264,11 @@ export function ResourceTelemetryDiagnostics({
1264 title="Instrumented application I/O"1264 title="Instrumented application I/O"
1265 icon={<DatabaseIcon className="size-4 text-muted-foreground" />}1265 icon={<DatabaseIcon className="size-4 text-muted-foreground" />}
1266 headerAction={1266 headerAction={
1267 <span className="text-[10px] text-muted-foreground/55">Logical bytes by operation</span>1267 <span className="text-3xs text-muted-foreground/55">Logical bytes by operation</span>
1268 }1268 }
1269 >1269 >
1270 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-[0_1px_1px_rgb(0_0_0/0.03)]">1270 <div className="overflow-hidden rounded-2xl border border-border/70 bg-card shadow-xs/5">
1271 <div className="bg-muted/15 px-4 py-3 text-[11px] leading-relaxed text-muted-foreground sm:px-5">1271 <div className="bg-muted/15 px-4 py-3 text-2xs leading-relaxed text-muted-foreground sm:px-5">
1272 Native counters identify which process is reading or writing. These application-level1272 Native counters identify which process is reading or writing. These application-level
1273 counters identify known T3 operations so process spikes can be correlated with specific1273 counters identify known T3 operations so process spikes can be correlated with specific
1274 persistence and logging paths.1274 persistence and logging paths.
apps/web/src/components/settings/SettingsPanels.tsx+4-4
...@@ -264,7 +264,7 @@ function AboutVersionTitle() {...@@ -264,7 +264,7 @@ function AboutVersionTitle() {
264 return (264 return (
265 <span className="inline-flex items-baseline gap-2">265 <span className="inline-flex items-baseline gap-2">
266 <span>Version</span>266 <span>Version</span>
267 <code className="text-[11px] font-medium text-muted-foreground">{APP_VERSION}</code>267 <code className="text-2xs font-medium text-muted-foreground">{APP_VERSION}</code>
268 </span>268 </span>
269 );269 );
270}270}
...@@ -1368,8 +1368,8 @@ export function AppearanceSettingsPanel() {...@@ -1368,8 +1368,8 @@ export function AppearanceSettingsPanel() {
1368 : "flex shrink-0 gap-1"1368 : "flex shrink-0 gap-1"
1369 }1369 }
1370 >1370 >
1371 <span className="size-2 rounded-full bg-[var(--diff-deletion)]" />1371 <span className="size-2 rounded-full bg-diff-deletion" />
1372 <span className="size-2 rounded-full bg-[var(--diff-addition)]" />1372 <span className="size-2 rounded-full bg-diff-addition" />
1373 </span>1373 </span>
1374 <SelectValue>1374 <SelectValue>
1375 {settings.diffColorScheme === "blue-orange" ? "Blue & orange" : "Red & green"}1375 {settings.diffColorScheme === "blue-orange" ? "Blue & orange" : "Red & green"}
...@@ -2046,7 +2046,7 @@ function LegacyFeaturesSection() {...@@ -2046,7 +2046,7 @@ function LegacyFeaturesSection() {
2046 <section id="legacy-features" ref={targetRef} tabIndex={-1} className="space-y-2.5">2046 <section id="legacy-features" ref={targetRef} tabIndex={-1} className="space-y-2.5">
2047 <Collapsible open={open} onOpenChange={setOpen}>2047 <Collapsible open={open} onOpenChange={setOpen}>
2048 <CollapsibleTrigger className="group flex min-h-8 w-full items-center gap-2 px-3 sm:px-4">2048 <CollapsibleTrigger className="group flex min-h-8 w-full items-center gap-2 px-3 sm:px-4">
2049 <h2 className="text-sm font-normal tracking-[-0.005em] text-foreground/70 transition-colors group-hover:text-foreground">2049 <h2 className="text-sm font-normal text-foreground/70 transition-colors group-hover:text-foreground">
2050 Legacy features2050 Legacy features
2051 </h2>2051 </h2>
2052 <ChevronRightIcon className="size-4 text-muted-foreground transition-transform duration-200 group-data-panel-open:rotate-90" />2052 <ChevronRightIcon className="size-4 text-muted-foreground transition-transform duration-200 group-data-panel-open:rotate-90" />
apps/web/src/components/settings/SettingsSidebarNav.tsx+1-1
...@@ -311,7 +311,7 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {...@@ -311,7 +311,7 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {
311 <span className="block truncate text-sm font-medium text-sidebar-foreground">311 <span className="block truncate text-sm font-medium text-sidebar-foreground">
312 {item.title}312 {item.title}
313 </span>313 </span>
314 <span className="block truncate text-[11px] text-sidebar-muted-foreground/75">314 <span className="block truncate text-2xs text-sidebar-muted-foreground/75">
315 {SETTINGS_SECTION_LABELS[item.to]}315 {SETTINGS_SECTION_LABELS[item.to]}
316 </span>316 </span>
317 </span>317 </span>
apps/web/src/components/settings/SnapShotSetupDialog.tsx+2-6
...@@ -268,9 +268,7 @@ export function SnapShotSetupDialog({...@@ -268,9 +268,7 @@ export function SnapShotSetupDialog({
268 permissions={[268 permissions={[
269 {269 {
270 id: "screenRecording",270 id: "screenRecording",
271 icon: (271 icon: <MacScreenRecordingIcon className="size-8 shrink-0 drop-shadow-sm" />,
272 <MacScreenRecordingIcon className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]" />
273 ),
274 title: "Screen Recording",272 title: "Screen Recording",
275 description: "Capture the window you're using.",273 description: "Capture the window you're using.",
276 granted: macPermissions.screenRecording,274 granted: macPermissions.screenRecording,
...@@ -278,9 +276,7 @@ export function SnapShotSetupDialog({...@@ -278,9 +276,7 @@ export function SnapShotSetupDialog({
278 },276 },
279 {277 {
280 id: "accessibility",278 id: "accessibility",
281 icon: (279 icon: <MacAccessibilityIcon className="size-8 shrink-0 drop-shadow-sm" />,
282 <MacAccessibilityIcon className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]" />
283 ),
284 title: "Accessibility",280 title: "Accessibility",
285 description: includeAccessibility281 description: includeAccessibility
286 ? "Include text and controls from the captured app."282 ? "Include text and controls from the captured app."
apps/web/src/components/settings/SourceControlSettings.tsx+4-6
...@@ -242,8 +242,8 @@ function itemSummary({...@@ -242,8 +242,8 @@ function itemSummary({
242 return (242 return (
243 <span>243 <span>
244 {item.label} is not authenticated on this server. Sign in or configure credentials using244 {item.label} is not authenticated on this server. Sign in or configure credentials using
245 the <code className="rounded bg-muted px-1 py-px text-[11px]">{item.executable}</code>{" "}245 the <code className="rounded bg-muted px-1 py-px text-2xs">{item.executable}</code> tool
246 tool on the server host to enable change request features.246 on the server host to enable change request features.
247 </span>247 </span>
248 );248 );
249 }249 }
...@@ -294,9 +294,7 @@ function DiscoveryItemRow({...@@ -294,9 +294,7 @@ function DiscoveryItemRow({
294 <div className="min-w-0 flex-1 space-y-1">294 <div className="min-w-0 flex-1 space-y-1">
295 <div className="flex min-w-0 flex-wrap items-center gap-2">295 <div className="flex min-w-0 flex-wrap items-center gap-2">
296 <SourceControlItemMark item={item} />296 <SourceControlItemMark item={item} />
297 <span className="truncate text-sm font-medium tracking-[-0.005em] text-foreground">297 <span className="truncate text-sm font-medium text-foreground">{item.label}</span>
298 {item.label}
299 </span>
300 {version ? <code className="text-xs text-muted-foreground">{version}</code> : null}298 {version ? <code className="text-xs text-muted-foreground">{version}</code> : null}
301 {isVcsNotReady(item) ? (299 {isVcsNotReady(item) ? (
302 <Badge variant="warning" size="sm">300 <Badge variant="warning" size="sm">
...@@ -309,7 +307,7 @@ function DiscoveryItemRow({...@@ -309,7 +307,7 @@ function DiscoveryItemRow({
309 </Badge>307 </Badge>
310 ) : null}308 ) : null}
311 </div>309 </div>
312 <p className="flex min-w-0 flex-wrap items-center gap-x-1 text-[13px] leading-[1.45] text-muted-foreground/80">310 <p className="flex min-w-0 flex-wrap items-center gap-x-1 text-xs leading-normal text-muted-foreground/80">
313 {itemSummary({ item, auth, authAccount })}311 {itemSummary({ item, auth, authAccount })}
314 </p>312 </p>
315 </div>313 </div>
apps/web/src/components/settings/ThemeColorPicker.tsx+4-4
...@@ -171,7 +171,7 @@ function ThemeColorPickerPanel({...@@ -171,7 +171,7 @@ function ThemeColorPickerPanel({
171 <div className="flex items-center justify-between border-b border-border/70 px-4 py-3">171 <div className="flex items-center justify-between border-b border-border/70 px-4 py-3">
172 <div className="min-w-0">172 <div className="min-w-0">
173 <p className="truncate text-xs font-semibold text-foreground">{label}</p>173 <p className="truncate text-xs font-semibold text-foreground">{label}</p>
174 <p className="text-[11px] text-muted-foreground">Choose a color</p>174 <p className="text-2xs text-muted-foreground">Choose a color</p>
175 </div>175 </div>
176 <span176 <span
177 className="size-7 shrink-0 rounded-full shadow-sm"177 className="size-7 shrink-0 rounded-full shadow-sm"
...@@ -193,7 +193,7 @@ function ThemeColorPickerPanel({...@@ -193,7 +193,7 @@ function ThemeColorPickerPanel({
193 />193 />
194 <div className="grid grid-cols-[1fr_1.2fr] gap-2">194 <div className="grid grid-cols-[1fr_1.2fr] gap-2">
195 <label className="grid min-w-0 gap-1">195 <label className="grid min-w-0 gap-1">
196 <span className="px-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">196 <span className="px-1 text-3xs font-semibold uppercase tracking-widest text-muted-foreground">
197 HEX197 HEX
198 </span>198 </span>
199 <span className="flex min-w-0 items-center gap-2 rounded-lg border border-input bg-background px-2 focus-within:border-ring">199 <span className="flex min-w-0 items-center gap-2 rounded-lg border border-input bg-background px-2 focus-within:border-ring">
...@@ -219,7 +219,7 @@ function ThemeColorPickerPanel({...@@ -219,7 +219,7 @@ function ThemeColorPickerPanel({
219 </span>219 </span>
220 </label>220 </label>
221 <label className="grid min-w-0 gap-1">221 <label className="grid min-w-0 gap-1">
222 <span className="px-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">222 <span className="px-1 text-3xs font-semibold uppercase tracking-widest text-muted-foreground">
223 RGB223 RGB
224 </span>224 </span>
225 <span className="flex min-w-0 items-center rounded-lg border border-input bg-background px-2 focus-within:border-ring">225 <span className="flex min-w-0 items-center rounded-lg border border-input bg-background px-2 focus-within:border-ring">
...@@ -323,7 +323,7 @@ export const ThemeColorField = memo(function ThemeColorField({...@@ -323,7 +323,7 @@ export const ThemeColorField = memo(function ThemeColorField({
323 <div323 <div
324 className={cn(324 className={cn(
325 "flex min-h-11 min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 transition-[background-color,box-shadow]",325 "flex min-h-11 min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 transition-[background-color,box-shadow]",
326 selected && "bg-accent/60 shadow-[inset_0_0_0_1px_var(--ring)]",326 selected && "bg-accent/60 inset-ring inset-ring-ring",
327 )}327 )}
328 data-theme-color-role={role}328 data-theme-color-role={role}
329 >329 >
apps/web/src/components/settings/ThemeImportDialog.tsx+4-4
...@@ -111,12 +111,12 @@ function ThemeJsonEditor({...@@ -111,12 +111,12 @@ function ThemeJsonEditor({
111 }, []);111 }, []);
112112
113 return (113 return (
114 <div className="relative overflow-hidden rounded-xl border border-input bg-background shadow-xs/5 focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/24">114 <div className="relative overflow-hidden rounded-xl border border-input bg-background shadow-xs/5 focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/24">
115 {isPlainText ? null : (115 {isPlainText ? null : (
116 <pre116 <pre
117 ref={highlightRef}117 ref={highlightRef}
118 aria-hidden118 aria-hidden
119 className="pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre-wrap break-words p-3 font-mono text-[12px] leading-5 text-foreground"119 className="pointer-events-none absolute inset-0 m-0 overflow-hidden whitespace-pre-wrap break-words p-3 font-mono text-xs leading-5 text-foreground"
120 >120 >
121 <code dangerouslySetInnerHTML={{ __html: highlightedJson }} />121 <code dangerouslySetInnerHTML={{ __html: highlightedJson }} />
122 </pre>122 </pre>
...@@ -124,7 +124,7 @@ function ThemeJsonEditor({...@@ -124,7 +124,7 @@ function ThemeJsonEditor({
124 <textarea124 <textarea
125 aria-label="Theme JSON"125 aria-label="Theme JSON"
126 className={cn(126 className={cn(
127 "relative z-10 block min-h-44 w-full resize-y overflow-auto bg-transparent p-3 font-mono text-[12px] leading-5 caret-foreground outline-none placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",127 "relative z-10 block min-h-44 w-full resize-y overflow-auto bg-transparent p-3 font-mono text-xs leading-5 caret-foreground outline-none placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",
128 isPlainText ? "text-foreground" : "text-transparent",128 isPlainText ? "text-foreground" : "text-transparent",
129 )}129 )}
130 id={id}130 id={id}
...@@ -438,7 +438,7 @@ export function ThemeImportDialog({...@@ -438,7 +438,7 @@ export function ThemeImportDialog({
438438
439 <div className="flex items-center gap-3" aria-hidden>439 <div className="flex items-center gap-3" aria-hidden>
440 <div className="h-px flex-1 bg-border" />440 <div className="h-px flex-1 bg-border" />
441 <span className="text-muted-foreground text-[11px] uppercase tracking-wider">441 <span className="text-muted-foreground text-2xs uppercase tracking-wider">
442 or import a file442 or import a file
443 </span>443 </span>
444 <div className="h-px flex-1 bg-border" />444 <div className="h-px flex-1 bg-border" />
apps/web/src/components/settings/ThemeSettings.tsx+5-5
...@@ -231,12 +231,12 @@ function ThemeLibraryCard({...@@ -231,12 +231,12 @@ function ThemeLibraryCard({
231 </button>231 </button>
232 </ThemeVariantTooltip>232 </ThemeVariantTooltip>
233 <span233 <span
234 className="pointer-events-none absolute bottom-0 left-1/2 inline-flex max-w-24 -translate-x-1/2 items-center gap-1 text-[11px] font-medium text-foreground"234 className="pointer-events-none absolute bottom-0 left-1/2 inline-flex max-w-24 -translate-x-1/2 items-center gap-1 text-2xs font-medium text-foreground"
235 style={{ marginLeft: rootOffsetX }}235 style={{ marginLeft: rootOffsetX }}
236 >236 >
237 <span className="truncate">{selected.option.label}</span>237 <span className="truncate">{selected.option.label}</span>
238 {options.length > 1 ? (238 {options.length > 1 ? (
239 <span className="shrink-0 rounded-full bg-muted px-1 text-[9px] text-muted-foreground">239 <span className="shrink-0 rounded-full bg-muted px-1 text-3xs text-muted-foreground">
240 +{options.length - 1}240 +{options.length - 1}
241 </span>241 </span>
242 ) : null}242 ) : null}
...@@ -256,7 +256,7 @@ function ThemeLibraryCard({...@@ -256,7 +256,7 @@ function ThemeLibraryCard({
256 aria-label={`Use ${option.label} for ${mode} mode${optionIsActive ? ", currently active" : ""}`}256 aria-label={`Use ${option.label} for ${mode} mode${optionIsActive ? ", currently active" : ""}`}
257 aria-pressed={optionIsActive}257 aria-pressed={optionIsActive}
258 className={cn(258 className={cn(
259 "absolute left-1/2 top-1 z-30 flex size-7 items-center justify-center rounded-full bg-background shadow-sm outline-none transition-[transform,opacity] duration-200 ease-out motion-reduce:transition-none focus-visible:ring-2 focus-visible:ring-ring",259 "absolute left-1/2 top-1 z-30 flex size-7 items-center justify-center rounded-full bg-background shadow-sm outline-none transition-[opacity,transform] duration-200 ease-out motion-reduce:transition-none focus-visible:ring-2 focus-visible:ring-ring",
260 optionIsActive ? "ring-2 ring-ring" : "ring-1 ring-border/70",260 optionIsActive ? "ring-2 ring-ring" : "ring-1 ring-border/70",
261 )}261 )}
262 style={{262 style={{
...@@ -884,12 +884,12 @@ export function ThemeLibrary({...@@ -884,12 +884,12 @@ export function ThemeLibrary({
884884
885 return (885 return (
886 <div className="space-y-3">886 <div className="space-y-3">
887 <h3 className="px-3 text-sm font-normal tracking-[-0.005em] text-foreground/70 sm:px-4">887 <h3 className="px-3 text-sm font-normal text-foreground/70 sm:px-4">
888 {searchableSetting("color-scheme").title}888 {searchableSetting("color-scheme").title}
889 </h3>889 </h3>
890 {renderModeTiles()}890 {renderModeTiles()}
891 <div className="flex min-h-8 flex-wrap items-center justify-between gap-3 px-3 pt-2 sm:px-4">891 <div className="flex min-h-8 flex-wrap items-center justify-between gap-3 px-3 pt-2 sm:px-4">
892 <h3 className="text-sm font-normal tracking-[-0.005em] text-foreground/70">892 <h3 className="text-sm font-normal text-foreground/70">
893 {searchableSetting("theme").title}893 {searchableSetting("theme").title}
894 </h3>894 </h3>
895 <div className="flex flex-wrap items-center justify-end gap-2">895 <div className="flex flex-wrap items-center justify-end gap-2">
apps/web/src/components/settings/ThemeWireframe.tsx+2-2
...@@ -66,7 +66,7 @@ function ThemeWireframePane({...@@ -66,7 +66,7 @@ function ThemeWireframePane({
6666
67 {/* Composer */}67 {/* Composer */}
68 <span68 <span
69 className="absolute bottom-[8%] left-[26%] right-[6%] flex h-[15%] items-center justify-between rounded-md px-[2.5%]"69 className="absolute bottom-[8%] left-[26%] right-[6%] flex h-[15%] items-center justify-between rounded-md px-1"
70 style={{70 style={{
71 backgroundColor: colors.surface,71 backgroundColor: colors.surface,
72 boxShadow: `inset 0 0 0 1px ${line}`,72 boxShadow: `inset 0 0 0 1px ${line}`,
...@@ -92,7 +92,7 @@ function ThemeWireframePane({...@@ -92,7 +92,7 @@ function ThemeWireframePane({
92 >92 >
93 {[0, 1, 2].map((row) => (93 {[0, 1, 2].map((row) => (
94 <span94 <span
95 className="absolute left-[11%] right-[11%] flex items-center gap-[5%]"95 className="absolute left-[11%] right-[11%] flex items-center gap-1"
96 key={row}96 key={row}
97 style={{ top: `${10 + row * 30}%`, height: "20%" }}97 style={{ top: `${10 + row * 30}%`, height: "20%" }}
98 >98 >
apps/web/src/components/settings/settingsLayout.tsx+4-4
...@@ -202,7 +202,7 @@ export function SettingsSection({...@@ -202,7 +202,7 @@ export function SettingsSection({
202 className="flex min-h-7 items-start justify-between gap-4 px-3 sm:px-4"202 className="flex min-h-7 items-start justify-between gap-4 px-3 sm:px-4"
203 >203 >
204 <div className="min-w-0">204 <div className="min-w-0">
205 <h2 className="flex min-h-7 items-center gap-2 text-sm font-normal tracking-[-0.005em] text-foreground/70">205 <h2 className="flex min-h-7 items-center gap-2 text-sm font-normal text-foreground/70">
206 {icon}206 {icon}
207 {title}207 {title}
208 </h2>208 </h2>
...@@ -228,7 +228,7 @@ export function SettingsUnavailableGroup({...@@ -228,7 +228,7 @@ export function SettingsUnavailableGroup({
228228
229 return (229 return (
230 <div className="border-border/60 bg-muted/20 py-1.5">230 <div className="border-border/60 bg-muted/20 py-1.5">
231 <div className="flex items-start gap-2 px-3 py-2 text-[12px] leading-relaxed text-muted-foreground sm:px-4">231 <div className="flex items-start gap-2 px-3 py-2 text-xs leading-relaxed text-muted-foreground sm:px-4">
232 <InfoIcon className="mt-0.5 size-3.5 shrink-0 text-warning" />232 <InfoIcon className="mt-0.5 size-3.5 shrink-0 text-warning" />
233 <p>{message}</p>233 <p>{message}</p>
234 </div>234 </div>
...@@ -435,7 +435,7 @@ export function SettingsRow({...@@ -435,7 +435,7 @@ export function SettingsRow({
435 <div className="flex flex-col gap-3 @min-[32rem]/settings-row:grid @min-[32rem]/settings-row:grid-cols-[minmax(0,1fr)_minmax(10rem,auto)] @min-[32rem]/settings-row:items-center @min-[32rem]/settings-row:gap-8">435 <div className="flex flex-col gap-3 @min-[32rem]/settings-row:grid @min-[32rem]/settings-row:grid-cols-[minmax(0,1fr)_minmax(10rem,auto)] @min-[32rem]/settings-row:items-center @min-[32rem]/settings-row:gap-8">
436 <div className="min-w-0 flex-1 space-y-1">436 <div className="min-w-0 flex-1 space-y-1">
437 <div className="flex min-h-5 items-center gap-1.5">437 <div className="flex min-h-5 items-center gap-1.5">
438 <h3 className="text-sm font-medium tracking-[-0.005em] text-foreground">{title}</h3>438 <h3 className="text-sm font-medium text-foreground">{title}</h3>
439 {renderedInheritance ? (439 {renderedInheritance ? (
440 <span className="inline-flex h-5 w-5 shrink-0 items-center justify-center">440 <span className="inline-flex h-5 w-5 shrink-0 items-center justify-center">
441 {renderedInheritance}441 {renderedInheritance}
...@@ -446,7 +446,7 @@ export function SettingsRow({...@@ -446,7 +446,7 @@ export function SettingsRow({
446 </span>446 </span>
447 </div>447 </div>
448 {description ? (448 {description ? (
449 <p className="max-w-xl text-[13px] leading-[1.45] text-muted-foreground/80">449 <p className="max-w-xl text-xs leading-normal text-muted-foreground/80">
450 {description}450 {description}
451 </p>451 </p>
452 ) : null}452 ) : null}
apps/web/src/components/sidebar/SidebarProviderUpdatePill.tsx+2-2
...@@ -125,7 +125,7 @@ export function SidebarProviderUpdatePill() {...@@ -125,7 +125,7 @@ export function SidebarProviderUpdatePill() {
125125
126 return (126 return (
127 <div127 <div
128 className={`group/provider-update relative flex min-h-7 w-full shrink-0 items-center overflow-hidden rounded-lg text-[11px] leading-4 font-medium transform-gpu transition-all duration-180 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform ${128 className={`group/provider-update relative flex min-h-7 w-full shrink-0 items-center overflow-hidden rounded-lg text-2xs leading-4 font-medium transform-gpu transition-all duration-180 ease-drawer will-change-transform ${
129 PROVIDER_UPDATE_PILL_STYLES[displayedView.tone]129 PROVIDER_UPDATE_PILL_STYLES[displayedView.tone]
130 } ${130 } ${
131 exitingKey === displayedView.key131 exitingKey === displayedView.key
...@@ -152,7 +152,7 @@ export function SidebarProviderUpdatePill() {...@@ -152,7 +152,7 @@ export function SidebarProviderUpdatePill() {
152 <div152 <div
153 key={displayedView.key}153 key={displayedView.key}
154 aria-hidden="true"154 aria-hidden="true"
155 className={`pointer-events-none absolute inset-y-0 left-0 w-full origin-left animate-[provider-update-pill-countdown_var(--provider-update-pill-dismiss-ms)_linear_forwards] border-r border-current/15 shadow-[inset_0_1px_0_rgb(255_255_255_/_0.08)] ${155 className={`pointer-events-none absolute inset-y-0 left-0 w-full origin-left scale-x-0 transition-transform duration-(--provider-update-pill-dismiss-ms) ease-linear starting:scale-x-100 border-r border-current/15 inset-shadow-2xs inset-shadow-white/8 ${
156 PROVIDER_UPDATE_PILL_PROGRESS_STYLES[displayedView.tone]156 PROVIDER_UPDATE_PILL_PROGRESS_STYLES[displayedView.tone]
157 }`}157 }`}
158 style={158 style={
apps/web/src/components/sidebar/SidebarThreadHeader.tsx+1-1
...@@ -83,7 +83,7 @@ export function SidebarThreadHeader({...@@ -83,7 +83,7 @@ export function SidebarThreadHeader({
83 ref={searchFieldRef}83 ref={searchFieldRef}
84 className="flex h-8 min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground"84 className="flex h-8 min-w-0 flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground"
85 >85 >
86 <SearchIcon className="size-4 shrink-0 text-[var(--sidebar-icon-color)]" />86 <SearchIcon className="size-4 shrink-0 text-(--sidebar-icon-color)" />
87 <SidebarInput87 <SidebarInput
88 ref={searchInputRef}88 ref={searchInputRef}
89 nativeInput89 nativeInput
apps/web/src/components/sidebar/SidebarUpdatePill.tsx+1-1
...@@ -311,7 +311,7 @@ function SidebarUpdateControl() {...@@ -311,7 +311,7 @@ function SidebarUpdateControl() {
311 !isInteractionDisabled && "hover:bg-sidebar-row-hover",311 !isInteractionDisabled && "hover:bg-sidebar-row-hover",
312 )312 )
313 : cn(313 : cn(
314 "text-[var(--sidebar-icon-color)]",314 "text-(--sidebar-icon-color)",
315 !isInteractionDisabled && "hover:bg-sidebar-row-hover hover:text-sidebar-foreground",315 !isInteractionDisabled && "hover:bg-sidebar-row-hover hover:text-sidebar-foreground",
316 ),316 ),
317 disabled && !showUpdateIconState && "opacity-60",317 disabled && !showUpdateIconState && "opacity-60",
apps/web/src/components/usage/UsageLimitsPooled.tsx+5-5
...@@ -52,7 +52,7 @@ function AccountChip({ email }: { readonly email: string }) {...@@ -52,7 +52,7 @@ function AccountChip({ email }: { readonly email: string }) {
52 <span52 <span
53 role="img"53 role="img"
54 aria-label={`Account ${accountInitials(email)}`}54 aria-label={`Account ${accountInitials(email)}`}
55 className="inline-flex size-4 shrink-0 items-center justify-center rounded-full text-[9px] leading-none font-semibold"55 className="inline-flex size-4 shrink-0 items-center justify-center rounded-full text-3xs leading-none font-semibold"
56 style={{ backgroundColor: `oklch(0.85 0.08 ${hue})`, color: `oklch(0.35 0.1 ${hue})` }}56 style={{ backgroundColor: `oklch(0.85 0.08 ${hue})`, color: `oklch(0.35 0.1 ${hue})` }}
57 >57 >
58 {accountInitials(email)}58 {accountInitials(email)}
...@@ -269,7 +269,7 @@ function PoolSegment({...@@ -269,7 +269,7 @@ function PoolSegment({
269 ) : null}269 ) : null}
270 <span270 <span
271 aria-hidden271 aria-hidden
272 className="absolute inset-0 flex items-center justify-center text-[10px] leading-none font-semibold text-foreground/80 tabular-nums @2xl/pool:hidden"272 className="absolute inset-0 flex items-center justify-center text-3xs leading-none font-semibold text-foreground/80 tabular-nums @2xl/pool:hidden"
273 >273 >
274 {index}274 {index}
275 </span>275 </span>
...@@ -277,7 +277,7 @@ function PoolSegment({...@@ -277,7 +277,7 @@ function PoolSegment({
277 <AccountName account={account} className="min-w-0 truncate font-medium text-foreground" />277 <AccountName account={account} className="min-w-0 truncate font-medium text-foreground" />
278 <span className="shrink-0 font-semibold text-foreground tabular-nums">{remaining}%</span>278 <span className="shrink-0 font-semibold text-foreground tabular-nums">{remaining}%</span>
279 {/* Countdown and badge get their own plate: fill and hatching run under them otherwise. */}279 {/* Countdown and badge get their own plate: fill and hatching run under them otherwise. */}
280 <span className="ms-auto flex shrink-0 items-center gap-1.5 rounded-sm bg-background/85 px-1.5 py-0.5 text-[11px] text-foreground tabular-nums">280 <span className="ms-auto flex shrink-0 items-center gap-1.5 rounded-sm bg-background/85 px-1.5 py-0.5 text-2xs text-foreground tabular-nums">
281 {resetsIn?.replace("resets in ", "↻ ") ?? ""}281 {resetsIn?.replace("resets in ", "↻ ") ?? ""}
282 {credits ? (282 {credits ? (
283 <>283 <>
...@@ -348,7 +348,7 @@ function LegendRow({...@@ -348,7 +348,7 @@ function LegendRow({
348 render={<Button variant="ghost" size="compact" />}348 render={<Button variant="ghost" size="compact" />}
349 className="min-w-0 @2xl/pool:hidden"349 className="min-w-0 @2xl/pool:hidden"
350 >350 >
351 <span className="relative inline-flex size-4 shrink-0 items-center justify-center rounded-sm text-[10px] leading-none font-semibold text-foreground/80 tabular-nums">351 <span className="relative inline-flex size-4 shrink-0 items-center justify-center rounded-sm text-3xs leading-none font-semibold text-foreground/80 tabular-nums">
352 <span352 <span
353 aria-hidden353 aria-hidden
354 className="absolute inset-0 rounded-sm opacity-35"354 className="absolute inset-0 rounded-sm opacity-35"
...@@ -359,7 +359,7 @@ function LegendRow({...@@ -359,7 +359,7 @@ function LegendRow({
359 </span>359 </span>
360 <AccountName account={account} className="min-w-0 truncate font-medium text-foreground" />360 <AccountName account={account} className="min-w-0 truncate font-medium text-foreground" />
361 <span className="shrink-0 font-semibold text-foreground tabular-nums">{remaining}%</span>361 <span className="shrink-0 font-semibold text-foreground tabular-nums">{remaining}%</span>
362 <span className="ms-auto flex shrink-0 items-center gap-1.5 text-[11px] text-muted-foreground tabular-nums">362 <span className="ms-auto flex shrink-0 items-center gap-1.5 text-2xs text-muted-foreground tabular-nums">
363 {resetsIn?.replace("resets in ", "↻ ") ?? ""}363 {resetsIn?.replace("resets in ", "↻ ") ?? ""}
364 {credits ? (364 {credits ? (
365 <>365 <>
apps/web/src/components/usage/UsagePage.tsx+1-1
...@@ -428,7 +428,7 @@ export function UsagePage() {...@@ -428,7 +428,7 @@ export function UsagePage() {
428 <span className="truncate">428 <span className="truncate">
429 {PROVIDER_PRESENTATION[provider].label}429 {PROVIDER_PRESENTATION[provider].label}
430 </span>430 </span>
431 <span className="shrink-0 whitespace-nowrap text-[11px] text-muted-foreground tabular-nums">431 <span className="shrink-0 whitespace-nowrap text-2xs text-muted-foreground tabular-nums">
432 {sessionLabel}432 {sessionLabel}
433 </span>433 </span>
434 </span>434 </span>
apps/web/src/components/usage/UsageProviderChart.tsx+2-2
...@@ -322,7 +322,7 @@ export function UsageProviderChart({...@@ -322,7 +322,7 @@ export function UsageProviderChart({
322 {ticks.map((tick) => (322 {ticks.map((tick) => (
323 <span323 <span
324 key={tick}324 key={tick}
325 className="absolute right-0 -translate-y-1/2 text-[10px] text-muted-foreground tabular-nums"325 className="absolute right-0 -translate-y-1/2 text-3xs text-muted-foreground tabular-nums"
326 style={{ top: `${(toY(tick) / VIEW_HEIGHT) * 100}%` }}326 style={{ top: `${(toY(tick) / VIEW_HEIGHT) * 100}%` }}
327 >327 >
328 {tick === 0 ? "0" : format(tick)}328 {tick === 0 ? "0" : format(tick)}
...@@ -434,7 +434,7 @@ export function UsageProviderChart({...@@ -434,7 +434,7 @@ export function UsageProviderChart({
434 </div>434 </div>
435 </div>435 </div>
436436
437 <div className="flex justify-between pl-16 text-[10px] text-muted-foreground uppercase">437 <div className="flex justify-between pl-16 text-3xs text-muted-foreground uppercase">
438 <span>{periods[0] === undefined ? "" : formatPeriod(periods[0])}</span>438 <span>{periods[0] === undefined ? "" : formatPeriod(periods[0])}</span>
439 <span>439 <span>
440 {periods[Math.floor(periods.length / 2)] === undefined440 {periods[Math.floor(periods.length / 2)] === undefined
apps/web/src/index.css+46-34
...@@ -116,6 +116,17 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil...@@ -116,6 +116,17 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil
116 --workspace-titlebar-control-size: 1.75rem;116 --workspace-titlebar-control-size: 1.75rem;
117 --workspace-titlebar-control-gap: 0.75rem;117 --workspace-titlebar-control-gap: 0.75rem;
118 --workspace-titlebar-scroll-fade-height: 1.5rem;118 --workspace-titlebar-scroll-fade-height: 1.5rem;
119 /* The prompt on phones: iOS zooms into any input under 16px on focus. */
120 --font-size-prompt-touch: max(var(--font-size-prompt, 1rem), 16px);
121 /* Horizontal gutter shared by the page header and the chat column, clear of
122 the device's safe area. */
123 --workspace-gutter: 0.75rem;
124 --workspace-gutter-start: calc(env(safe-area-inset-left) + var(--workspace-gutter));
125 --workspace-gutter-end: calc(env(safe-area-inset-right) + var(--workspace-gutter));
126
127 @variant sm {
128 --workspace-gutter: 1.25rem;
129 }
119130
120 @variant dark {131 @variant dark {
121 --appearance-contrast-target: white;132 --appearance-contrast-target: white;
...@@ -148,6 +159,41 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil...@@ -148,6 +159,41 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil
148}159}
149160
150@theme inline {161@theme inline {
162 /* Two steps below Tailwind's text-xs (12px) for dense UI: metadata rows,
163 badges, counters, keyboard hints and diagnostics tables. 2xs is 11px,
164 3xs is 10px and the floor of the scale. Registered with tailwind-merge in
165 lib/utils.ts so cn() treats them as font sizes, not colours. */
166 --text-2xs: 0.6875rem;
167 --text-2xs--line-height: calc(1 / 0.6875);
168 --text-3xs: 0.625rem;
169 --text-3xs--line-height: calc(0.875 / 0.625);
170 /* Motion. drawer is the decelerating curve for surfaces that slide or pop in
171 (composer context, pills). */
172 --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
173 /* The composer's elevation: a soft drop pulled in under the surface, shared
174 by the composer, its context strip and attached banners. */
175 --shadow-composer: 0 12px 28px -18px rgb(0 0 0 / 40%);
176 --shadow-composer-dark: 0 14px 32px -18px rgb(0 0 0 / 75%);
177 /* Dark-mode shade where an attached surface meets the composer: 10px of
178 shadow fading away from the seam. Inline, so the offsets resolve on the
179 element. below: the context strip under the composer (1rem seam, faint
180 white fill). above: an attached banner over it (its tint on top). */
181 --background-image-composer-seam-below:
182 linear-gradient(
183 to bottom,
184 transparent 0 1rem,
185 rgb(0 0 0 / 18%) 1rem,
186 transparent calc(1rem + 10px)
187 ),
188 linear-gradient(rgb(255 255 255 / 1%), rgb(255 255 255 / 1%));
189 --background-image-composer-seam-above:
190 linear-gradient(var(--chat-composer-attached-tint), var(--chat-composer-attached-tint)),
191 linear-gradient(
192 to top,
193 transparent 0 var(--chat-composer-attachment-overlap),
194 rgb(0 0 0 / 18%) var(--chat-composer-attachment-overlap),
195 transparent calc(var(--chat-composer-attachment-overlap) + 10px)
196 );
151 --color-zinc-25: oklch(99.2% 0 0);197 --color-zinc-25: oklch(99.2% 0 0);
152 --animate-skeleton: skeleton 2.4s infinite;198 --animate-skeleton: skeleton 2.4s infinite;
153 /* Duty-cycled indicator animations: long holds with stepped ramps, so the199 /* Duty-cycled indicator animations: long holds with stepped ramps, so the
...@@ -1936,40 +1982,6 @@ code {...@@ -1936,40 +1982,6 @@ code {
1936 overflow-wrap: anywhere;1982 overflow-wrap: anywhere;
1937}1983}
19381984
1939/* Prompt-stash save acknowledgement: the new count fades up from just below
1940 its resting position, once, then stops. One-shot and event-driven (React
1941 remounts the element by key on each stash) — no continuous animation. */
1942@keyframes prompt-stash-count-enter {
1943 from {
1944 opacity: 0;
1945 transform: translateY(2px);
1946 }
1947 to {
1948 opacity: 1;
1949 transform: translateY(0);
1950 }
1951}
1952
1953/* Expanded capture preview swaps between the screenshot and its extracted text.
1954 One-shot fade on whichever panel mounts, so nothing repaints continuously. */
1955@keyframes snap-shot-contents-enter {
1956 from {
1957 opacity: 0;
1958 }
1959 to {
1960 opacity: 1;
1961 }
1962}
1963
1964@keyframes provider-update-pill-countdown {
1965 from {
1966 transform: scaleX(1);
1967 }
1968 to {
1969 transform: scaleX(0);
1970 }
1971}
1972
1973:root {1985:root {
1974 --diff-addition: var(--success);1986 --diff-addition: var(--success);
1975 --diff-deletion: var(--destructive);1987 --diff-deletion: var(--destructive);
apps/web/src/lib/utils.ts+5-1
...@@ -1,9 +1,13 @@...@@ -1,9 +1,13 @@
1import { MessageId, ProjectId, ThreadId } from "@t3tools/contracts";1import { MessageId, ProjectId, ThreadId } from "@t3tools/contracts";
2import { type CxOptions, cx } from "class-variance-authority";2import { type CxOptions, cx } from "class-variance-authority";
3import * as Encoding from "effect/Encoding";3import * as Encoding from "effect/Encoding";
4import { twMerge } from "tailwind-merge";4import { extendTailwindMerge } from "tailwind-merge";
5import { DraftId } from "../composerDraftStore";5import { DraftId } from "../composerDraftStore";
66
7// The theme's extra font sizes (index.css). Unregistered, tailwind-merge reads
8// text-2xs as a colour and drops it next to text-muted-foreground.
9const twMerge = extendTailwindMerge({ extend: { theme: { text: ["2xs", "3xs"] } } });
10
7export function cn(...inputs: CxOptions) {11export function cn(...inputs: CxOptions) {
8 return twMerge(cx(inputs));12 return twMerge(cx(inputs));
9}13}
vite.config.ts+40
...@@ -225,6 +225,41 @@ export default defineConfig({...@@ -225,6 +225,41 @@ export default defineConfig({
225 rules: {225 rules: {
226 // A className built at runtime on a ui component is one no-restyle cannot read.226 // A className built at runtime on a ui component is one no-restyle cannot read.
227 "shadcn/require-static-classes": "error",227 "shadcn/require-static-classes": "error",
228 // Appearance values come from the theme and Tailwind's scales. Layout stays free
229 // (placement belongs to the parent); the other entries are values no scale can hold.
230 "shadcn/no-arbitrary-values": [
231 "error",
232 {
233 allow: [
234 "layout",
235 // Which properties an element animates is per-element behaviour, like layout,
236 // not a design value; timing curves and durations still come from the theme.
237 "transition",
238 // Overlays that follow their frame's corner, which is set at runtime
239 // (floating preview) or by the element they decorate (composer outline).
240 "rounded-[inherit]",
241 // Inline chips size in em so they scale with the text they sit in
242 // (the composer honours the prompt font-size preference).
243 "gap-[0.33em]",
244 "px-[0.5em]",
245 "rounded-[0.5em]",
246 "text-[0.86em]",
247 // Project icons render from 14px to 48px and keep one proportional corner.
248 "rounded-[25%]",
249 // An emoji project icon fills its container, whatever size the parent gives it.
250 "text-[length:80cqh]",
251 // The platform's own selection colour on a selected composer chip.
252 "bg-[Highlight]",
253 // Brand marks keep their brand colours (Cursor, Grok, Claude).
254 "fill-[#26251E]",
255 "fill-[#EDECEC]",
256 "fill-[#0F0F0F]",
257 "fill-[#F5F5F5]",
258 "fill-[#d97757]",
259 "text-[#d97757]",
260 ],
261 },
262 ],
228 "shadcn/no-restyle": [263 "shadcn/no-restyle": [
229 "error",264 "error",
230 {265 {
...@@ -242,6 +277,11 @@ export default defineConfig({...@@ -242,6 +277,11 @@ export default defineConfig({
242 ],277 ],
243 },278 },
244 },279 },
280 {
281 // The sign-in masthead is T3 brand artwork: fixed gradients, not theme surfaces.
282 files: ["apps/web/src/components/auth/AuthSurfaceShell.tsx"],
283 rules: { "shadcn/no-arbitrary-values": "off" },
284 },
245 {285 {
246 // Shared client code must not call APIs missing from Hermes. Our ESNext286 // Shared client code must not call APIs missing from Hermes. Our ESNext
247 // TypeScript target accepts them even when they would crash mobile at launch.287 // TypeScript target accepts them even when they would crash mobile at launch.