Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .claude/rules/sim-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ setWidth: (width) => {

## Text Scale

Custom font sizes (the `@theme` block in `apps/sim/app/_styles/globals.css`): `text-micro`=10px, `text-xs`=11px, `text-caption`=12px, `text-small`=13px, `text-base`=15px. `text-sm` is Tailwind default 14px. Field titles use `text-small` (13px); hints/errors use `text-caption` (12px).
Use the named scale in `apps/sim/app/_styles/globals.css`: `text-micro`=10px, `text-xs`=11px, `text-caption`=12px, `text-small`=13px, `text-base`=15px, `text-md`=16px, `text-title`=28px, `text-title-lg`=32px, and `text-display`=40px. The explicitly adopted stock entries retain their rem units and default leading: `text-sm`=0.875rem, `text-xl`=1.25rem, and `text-2xl`=1.5rem (14/20/24px at the default root size). Field titles use `text-small`; hints/errors use `text-caption`; workflow titles use `text-md`.

Preserve explicit line heights when replacing arbitrary sizes. Where the old size inherited its line height, use `leading-[inherit]` if the named utility would otherwise add a different default. Keep document-relative heading/code recipes and the thinking loader's proportional label sizing distinct from ordinary UI text.

Use `font-inter` within the existing scoped Inter loading boundary; the utility does not load the font globally. Keep monospace for code, JSON, and credentials.

Icons default `size-[14px]`. Equal h/w → `size-*` (`size-[14px]`, `size-4`), never `h-N w-N`.

Expand All @@ -67,7 +71,7 @@ A scroll region that can hide rows past an edge uses `useScrollEdges` with `scro

## Font Weight

Three steps, Tailwind's stock scale, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class only to step *up* from body.
Three steps, explicitly adopted from Tailwind's stock scale in globals.css, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class to step *up* from body or to reset meaningful inherited weight. Raw CSS references the same `--font-weight-normal`, `--font-weight-medium`, and `--font-weight-semibold` definitions; their values remain 400/500/600.

Never write an arbitrary weight (`font-[380]`, `font-[430]`, `font-[450]`, …), and never set `fontWeight` in an inline `style`. There was previously a CSS-variable weight scale (`--font-weight-base/medium/semibold`, remapping `font-medium` to 440/480) plus seven ad-hoc values clustered between 380 and 500; it was deleted because nothing read as hierarchical. Off-scale values are only acceptable where the design system genuinely cannot reach — react-email templates and the static `apps/sim/emails/broadcasts/*.html`, which email clients render without CSS variables.

Expand Down
8 changes: 6 additions & 2 deletions .cursor/rules/sim-styling.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ setWidth: (width) => {

## Text Scale

Custom font sizes (the `@theme` block in `apps/sim/app/_styles/globals.css`): `text-micro`=10px, `text-xs`=11px, `text-caption`=12px, `text-small`=13px, `text-base`=15px. `text-sm` is Tailwind default 14px. Field titles use `text-small` (13px); hints/errors use `text-caption` (12px).
Use the named scale in `apps/sim/app/_styles/globals.css`: `text-micro`=10px, `text-xs`=11px, `text-caption`=12px, `text-small`=13px, `text-base`=15px, `text-md`=16px, `text-title`=28px, `text-title-lg`=32px, and `text-display`=40px. The explicitly adopted stock entries retain their rem units and default leading: `text-sm`=0.875rem, `text-xl`=1.25rem, and `text-2xl`=1.5rem (14/20/24px at the default root size). Field titles use `text-small`; hints/errors use `text-caption`; workflow titles use `text-md`.

Preserve explicit line heights when replacing arbitrary sizes. Where the old size inherited its line height, use `leading-[inherit]` if the named utility would otherwise add a different default. Keep document-relative heading/code recipes and the thinking loader's proportional label sizing distinct from ordinary UI text.

Use `font-inter` within the existing scoped Inter loading boundary; the utility does not load the font globally. Keep monospace for code, JSON, and credentials.

Icons default `size-[14px]`. Equal h/w → `size-*` (`size-[14px]`, `size-4`), never `h-N w-N`.

Expand All @@ -67,7 +71,7 @@ A scroll region that can hide rows past an edge uses `useScrollEdges` with `scro

## Font Weight

Three steps, Tailwind's stock scale, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class only to step *up* from body.
Three steps, explicitly adopted from Tailwind's stock scale in globals.css, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class to step *up* from body or to reset meaningful inherited weight. Raw CSS references the same `--font-weight-normal`, `--font-weight-medium`, and `--font-weight-semibold` definitions; their values remain 400/500/600.

Never write an arbitrary weight (`font-[380]`, `font-[430]`, `font-[450]`, …), and never set `fontWeight` in an inline `style`. There was previously a CSS-variable weight scale (`--font-weight-base/medium/semibold`, remapping `font-medium` to 440/480) plus seven ad-hoc values clustered between 380 and 500; it was deleted because nothing read as hierarchical. Off-scale values are only acceptable where the design system genuinely cannot reach — react-email templates and the static `apps/sim/emails/broadcasts/*.html`, which email clients render without CSS variables.

Expand Down
4 changes: 3 additions & 1 deletion apps/sim/app/(auth)/components/auth-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ interface AuthHeaderProps {
export function AuthHeader({ title, description }: AuthHeaderProps) {
return (
<div className='space-y-1 text-center'>
<h1 className='text-balance text-[32px] text-[var(--text-primary)] leading-[1.2]'>{title}</h1>
<h1 className='text-balance text-[var(--text-primary)] text-title-lg leading-[1.2]'>
{title}
</h1>
{description != null && (
<p className='text-[var(--text-muted)] text-base leading-[1.5]'>{description}</p>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export default function EmailAuth({ identifier }: EmailAuthProps) {
</p>
</div>

<div className='text-center font-light text-sm'>
<div className='text-center font-normal text-sm'>
<button
onClick={() => {
setShowOtpVerification(false)
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/(interfaces)/chat/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export const ChatInput: React.FC<{
) : (
<div className='flex h-full w-full flex-col items-center justify-center gap-0.5 text-[var(--text-muted)]'>
<Paperclip className='size-[18px]' />
<span className='max-w-[48px] truncate px-[2px] text-[9px]'>
<span className='max-w-[48px] truncate px-[2px] text-micro'>
{file.name.split('.').pop()}
</span>
</div>
Expand Down Expand Up @@ -214,7 +214,7 @@ export const ChatInput: React.FC<{
onKeyDown={handleKeyDown}
placeholder={isDragOver ? 'Drop files here...' : 'Enter a message...'}
rows={1}
className='m-0 h-auto min-h-[24px] w-full resize-none overflow-y-auto overflow-x-hidden border-0 bg-transparent p-1 text-[15px] text-[var(--text-primary)] leading-[24px] caret-[var(--text-primary)] outline-hidden [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0 [&::-webkit-scrollbar]:hidden'
className='m-0 h-auto min-h-[24px] w-full resize-none overflow-y-auto overflow-x-hidden border-0 bg-transparent p-1 text-[var(--text-primary)] text-base leading-[24px] caret-[var(--text-primary)] outline-hidden [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0 [&::-webkit-scrollbar]:hidden'
/>

<div className='flex items-center justify-between'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function renderStructuredValuePreview(value: unknown) {
className='max-h-[220px]'
/>
{truncated && (
<p className='mt-1 text-[11px] text-[var(--text-muted)]'>
<p className='mt-1 text-[var(--text-muted)] text-xs leading-[inherit]'>
Value truncated for preview ({DISPLAY_VALUE_PREVIEW_MAX_CHARS.toLocaleString()} of{' '}
{prettyPrinted.length.toLocaleString()} characters shown).
</p>
Expand All @@ -162,7 +162,7 @@ function renderStructuredValuePreview(value: unknown) {
{truncated ? `${stringValue}…` : stringValue}
</div>
{truncated && (
<p className='mt-1 text-[11px] text-[var(--text-muted)]'>
<p className='mt-1 text-[var(--text-muted)] text-xs leading-[inherit]'>
Value truncated for preview ({DISPLAY_VALUE_PREVIEW_MAX_CHARS.toLocaleString()} of{' '}
{String(value).length.toLocaleString()} characters shown).
</p>
Expand Down Expand Up @@ -774,8 +774,10 @@ export default function ResumeExecutionPage({
{/* Header */}
<div className='mb-8 flex items-center justify-between'>
<div>
<h1 className='text-[20px] text-[var(--text-primary)]'>Paused Execution</h1>
<p className='mt-1 text-[14px] text-[var(--text-secondary)]'>
<h1 className='text-[var(--text-primary)] text-xl leading-[inherit]'>
Paused Execution
</h1>
<p className='mt-1 text-[var(--text-secondary)] text-sm leading-[inherit]'>
Select a pause point to review and resume
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ export function StageBlockCard({
hasContentBelowHeader ? 'h-[40px]' : 'h-[48px]'
)}
>
<span className='min-w-0 flex-1 truncate text-[17px] text-[var(--text-primary)]'>
<span className='min-w-0 flex-1 truncate text-[var(--text-primary)] text-md'>
{block.name}
</span>
<WorkflowTypeTag
Expand Down
22 changes: 18 additions & 4 deletions apps/sim/app/_styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"Noto Color Emoji";

--font-season: var(--font-season);
--font-inter: var(--font-inter);
--font-body:
ui-sans-serif, -apple-system, system-ui, Segoe UI, Helvetica, Apple Color Emoji, Arial,
sans-serif, Segoe UI Emoji, Segoe UI Symbol;
Expand All @@ -90,19 +91,32 @@
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;

--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;

--text-micro: 10px;
/**
* `xs` is the one size here that also exists in Tailwind's own scale, so it
* inherits `--text-xs--line-height` unless that is overridden too. v4's ratio
* (4/3) against an 11px size yields 14.67px, where v3 resolved 16.5px; the
* paired value keeps the leading where it was.
* Tailwind pairs `xs` with a default line-height ratio. Its v4 ratio (4/3)
* against our 11px size yields 14.67px; the explicit 1.5 preserves the
* existing 16.5px leading.
*/
--text-xs: 11px;
--text-xs--line-height: 1.5;
--text-caption: 12px;
--text-small: 13px;
/** Adopt the imported scale without changing its rem units or default leading. */
--text-sm: 0.875rem;
Comment thread
BillLeoutsakosvl346 marked this conversation as resolved.
--text-sm--line-height: calc(1.25 / 0.875);
--text-base: 15px;
--text-md: 16px;
--text-xl: 1.25rem;
--text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
--text-title: 28px;
--text-title-lg: 32px;
--text-display: 40px;

/**
* Hairline scale key. Overriding `spacing` rather than `width`/`height` keeps
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/cli/auth/cli-auth-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export function CliAuthView() {
<div className='space-y-4'>
<div className='flex items-center justify-center rounded-[10px] border border-[var(--border-1)] py-5'>
{/* `pl` offsets the trailing letter-space `tracking` adds after the last glyph, which would otherwise pull the code left of optical center. */}
<code className='pl-[0.2em] font-mono text-[28px] text-[var(--text-primary)] leading-none tracking-[0.2em]'>
<code className='pl-[0.2em] font-mono text-[var(--text-primary)] text-title leading-none tracking-[0.2em]'>
{request.pairing}
</code>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/f/[token]/public-file-email-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export function PublicFileEmailAuth({ token }: PublicFileEmailAuthProps) {
</p>
</div>

<div className='text-center font-light text-sm'>
<div className='text-center font-normal text-sm'>
<button
onClick={() => {
setSent(false)
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/invite/components/status-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function InviteStatusCard({
return (
<>
<div className='space-y-1 text-center'>
<h1 className='text-[32px] text-[var(--text-primary)] tracking-tight'>Loading</h1>
<h1 className='text-[var(--text-primary)] text-title-lg tracking-tight'>Loading</h1>
<p className='text-[var(--text-muted)]'>{description}</p>
</div>
<div className='mt-8 flex w-full items-center justify-center py-8'>
Expand All @@ -51,7 +51,7 @@ export function InviteStatusCard({
return (
<>
<div className='space-y-1 text-center'>
<h1 className='text-[32px] text-[var(--text-primary)] tracking-tight'>{title}</h1>
<h1 className='text-[var(--text-primary)] text-title-lg tracking-tight'>{title}</h1>
<p className='text-[var(--text-muted)]'>{description}</p>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function Composer({
placeholder={placeholder}
aria-label='Ask Sim'
rows={1}
className='field-sizing-content m-0 box-border min-h-[24px] w-full resize-none border-0 bg-transparent px-1 py-1 font-body text-[14px] text-[var(--text-primary)] leading-[24px] tracking-[-0.015em] outline-hidden [overflow-wrap:anywhere] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0'
className='field-sizing-content m-0 box-border min-h-[24px] w-full resize-none border-0 bg-transparent px-1 py-1 font-body text-[var(--text-primary)] text-sm leading-[24px] tracking-[-0.015em] outline-hidden [overflow-wrap:anywhere] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0'
/>
</div>

Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/o/[organizationId]/home/organization-home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function OrganizationHomeContent({ userName, chatId }: OrganizationHomeProps) {
<div className='min-h-0 flex-1 overflow-y-auto [scrollbar-gutter:stable_both-edges]'>
{/* Asymmetric padding biases the group up so the full cluster (heading + input + steps) sits at the optical center */}
<div className='flex min-h-full flex-col items-center justify-center px-6 pt-[2vh] pb-[22vh]'>
<h1 className='mb-7 max-w-chat text-balance font-season text-[26px] text-[var(--text-primary)] leading-[1.15] tracking-[-0.01em] sm:text-[28px]'>
<h1 className='mb-7 max-w-chat text-balance font-season text-2xl text-[var(--text-primary)] leading-[1.15] tracking-[-0.01em] sm:text-title'>
What should we get done{firstName ? `, ${firstName}` : ''}?
</h1>
<div className='relative w-full max-w-chat'>
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/o/[organizationId]/search/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function SearchField({
aria-label='Search your sources'
autoComplete='off'
spellCheck={false}
className='h-full min-w-0 flex-1 bg-transparent font-body text-[14px] text-[var(--text-primary)] tracking-[-0.015em] outline-hidden placeholder:text-[var(--text-muted)] [&::-webkit-search-cancel-button]:hidden'
className='h-full min-w-0 flex-1 bg-transparent font-body text-[var(--text-primary)] text-sm leading-[inherit] tracking-[-0.015em] outline-hidden placeholder:text-[var(--text-muted)] [&::-webkit-search-cancel-button]:hidden'
/>
<div className='flex shrink-0 items-center gap-1.5'>
{voice.isSupported && (
Expand Down Expand Up @@ -190,7 +190,7 @@ function OrganizationSearchContent() {
) : (
<div className='min-h-0 flex-1 overflow-y-auto [scrollbar-gutter:stable_both-edges]'>
<div className='flex min-h-full flex-col items-center justify-center px-6 pt-[2vh] pb-[22vh]'>
<h1 className='mb-7 max-w-chat text-balance text-center font-season text-[26px] text-[var(--text-primary)] leading-[1.15] tracking-[-0.01em] sm:text-[28px]'>
<h1 className='mb-7 max-w-chat text-balance text-center font-season text-2xl text-[var(--text-primary)] leading-[1.15] tracking-[-0.01em] sm:text-title'>
Search {organization.name}
</h1>
<div className='w-full max-w-chat'>
Expand Down
12 changes: 6 additions & 6 deletions apps/sim/app/unsubscribe/unsubscribe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function UnsubscribeContent() {
return (
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>Loading</h1>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>Loading</h1>
<p className={'text-[var(--text-muted)] text-md'}>Validating your unsubscribe link…</p>
</div>
<div className={'mt-8 flex w-full items-center justify-center py-8'}>
Expand All @@ -54,7 +54,7 @@ function UnsubscribeContent() {
return (
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>
Invalid Unsubscribe Link
</h1>
<p className={'text-[var(--text-muted)] text-md'}>{error}</p>
Expand All @@ -73,7 +73,7 @@ function UnsubscribeContent() {
return (
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>
Important Account Emails
</h1>
<p className={'text-[var(--text-muted)] text-md'}>
Expand All @@ -95,7 +95,7 @@ function UnsubscribeContent() {
return (
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>
Successfully Unsubscribed
</h1>
<p className={'text-[var(--text-muted)] text-md'}>
Expand All @@ -118,7 +118,7 @@ function UnsubscribeContent() {
return (
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>
Email Preferences
</h1>
<p className={'text-[var(--text-muted)] text-md'}>
Expand Down Expand Up @@ -206,7 +206,7 @@ export default function Unsubscribe() {
fallback={
<InviteLayout>
<div className='space-y-1 text-center'>
<h1 className={'text-[32px] text-[var(--text-primary)] tracking-tight'}>Loading</h1>
<h1 className={'text-[var(--text-primary)] text-title-lg tracking-tight'}>Loading</h1>
<p className={'text-[var(--text-muted)] text-md'}>Validating your unsubscribe link…</p>
</div>
<div className={'mt-8 flex w-full items-center justify-center py-8'}>
Expand Down
Loading
Loading