Sangria DS

Tokens

Tokens & themes

Semantic tokens come from the app's own globals.css token layer; themes are imported from shared/themes.ts. Both are checked against the app by bun run check:sync.

Semantic tokens

Stored as bare HSL triples so Tailwind can compose alpha — hsl(var(--primary) / .9).

--background
Page ground
--foreground
Body text
--primary
Primary action
--primary-accent
Links, own reactions
--secondary
Secondary surface
--muted
Muted surface
--muted-foreground
Meta text
--accent
Hover surface
--destructive
Destructive
--border
Hairlines
--input
Field borders
--ring
Focus ring

Surfaces & depth

Three layers. Depth comes from panels floating on a themed frame, not from borders between flush columns. Shown in the Classic theme.

List panel
Content panel
Frametheme.sidebar

Toolbar, rail and every gutter. One continuous ground; the toolbar is transparent on it.

List paneltheme.workspaceSidebar

Channel list. Floats on the frame with an inset white/6% ring.

Content panel--background

Main canvas and thread. Floats on the frame with a soft 0 1px 3px shadow.

Panel radius12pxrounded-xl · phone list 16px, phone chat 18px top corners only
Panel gap6pxbetween panels and to the frame edge · phone list 8px
Rail72px38px tiles, rounded-[10px], 11px bold labels
List row30pxrounded-[7px] · 44px on phone
Pane header54pxmd and up: channel, DM, group DM, thread, profile, drafts, threads, user group panel, new message, and the list's workspace header · Activity and Saved have their own · phone bars are min 56px
Search pill32pxrounded-[9px], white/13% on the frame · shows ⌘J (Ctrl + J off Mac), which opens the quick switcher

Theme accent

--theme-accent is the workspace theme's accent.light or accent.dark, resolved for the current mode. It is a hex, not an HSL triple, so read it as var(--theme-accent, hsl(var(--primary-accent))) and tint with color-mix rather than Tailwind's /alpha. --theme-badge is always the theme's pastel accent.dark, whatever the mode, and count pills put #16090e text on it.

workspace-shell.tsx sets both variables twice: inline on the shell root, and on <html> from an effect that removes them on unmount. Sheets, dialogs and popovers portal to <body>, outside the shell root, and only inherit the accent because it also lives on <html>.

--theme-accent
Send, reply count, NEW
accentTintBg
Open thread, file icon, selected rows
withAlpha(accent, .12)
Own reaction
--theme-badge
Count pills (#16090e text)
--primary-accent
Fallback outside a workspace

Helpers in src/lib/accent.ts

Every class helper falls back to --primary-accent outside a workspace and is written as a full literal so Tailwind's scanner finds it. This site imports a verbatim copy, held to the app by check:sync.

withAlpha(hex, alpha)Appends an alpha byte to a theme hex, for inline styles where only the per-mode hex is at hand. Own reactions use withAlpha(accent, 0.12).
accentTextAccent-coloured text: reply counts, the NEW divider, thread bar, saved-state icon, underline tab labels.
accentTintBgThe accent tint, 8% light / 15% dark: the open thread's parent, file icons, the group-DM hero's name chip, a selected theme card or huddle invitee. Rendered @mentions use the same mix, written in globals.css.
accentBorderAccent border: underline tabs, the selected mode button and theme card.
accentSelectedaccentTintBg + the same tint on hover + accentText. The shared selected-row style; the tint holds under the pointer instead of flipping to the grey hover.

Type scale

Lato, with a system stack behind it. Titles and sender names use 900, font-black; 700 stays for controls, labels and page chrome.

3xl / 700Page title
xl / 700Section heading
lg / 900Workspace, channel, thread title
base / 900Sender name
base / 400Message body
sm / 500Control label
xs / 400Timestamp, counts
tabular00:42 · 1,219 · 17

Workspace themes

17 palettes. The bar is each theme's rail colour; the two dots are its accent.light and accent.dark.

Classicdefault
Onyxonyx
Auroraaurora
Nebulanebula
Forestforest
Emberember
Slateslate
Roserose
Monokaimonokai
Draculadracula
Nordnord
Solarized Darksolarized_dark
Gruvbox Darkgruvbox_dark
One Darkone_dark
Materialmaterial
GitHubgithub
Claudeclaude

Each theme also defines a lighter workspaceSidebar for the channel list panel, so the frame and list read as two depths. Only the rail is shown here, and gradients are reduced to their first stop.