LetzAI Design System

Internal reference for the LetzAI product shell — typography, materials, and components that match canvas chrome.

Design system v1.7 · June 2026

Preview theme

Principles

LetzAI uses an Apple-like neutral palette. Hierarchy comes from opacity and weight, not color accents in the app shell.

  • Accent = ink. --accentcolor resolves to --color. No product purple in app chrome.
  • Marketing exception. Landing pages (.lp2) may use --marketing-accent, scoped to marketing CSS only.
  • Canvas exception. User strokes and picks can be any color; default focus/selection chrome uses ink.
  • Marketing heroes use --text-display-hero (landing .lp2-hero h1).
  • Canvas typography. In-product headings use the compact canvas scale (--text-page-title through --text-panel-label), not global h1h6.
  • Materials. Frosted chrome uses blur + translucent surfaces — not tinted glass.
  • Design artifacts. Sandboxed iframe designs use public/design-starters/*/tokens.css — separate from the app shell.

Control decision tree

App-wide actions.stdbutton / .altbutton in app-buttons.css
Canvas chrome.cv-* in canvas.css — toolbars, inspector, pills
DropdownsAppListSelect / .app-dropdown — not native <select>
Legacystyles.css patterns — migrate, do not extend

Color

Semantic tokens for the active preview theme. Semantic greens/reds are for feedback only — not decorative chrome.

Text hierarchy

--colorInk / primary text
--text-secondarySecondary text
--text-tertiaryTertiary text

Surfaces

--bgPage background
--verylightbgSubtle surface
--popupbgPopup / panel
--headerbgHeader
--surface-chromeFrosted chrome
--scrim-defaultModal scrim
--scrim-denseDense scrim (no blur)
--modalbgModal tint
--skeleton-baseSkeleton base

Interactive / chrome

--hairlineHairline border
--bordercolorBorder
--buttonbgButton fill
--lighthoverHover fill
--stdbuttonbgPrimary fill (= ink)
--stdbuttoncolorPrimary fill text
--accentcolorAccent (= ink)
--focus-ringFocus ring
--control-font-sizeCanvas control text
--control-height-mdCanvas control height

Semantic (feedback only)

--color-successSuccess
--color-errorError
--color-warningWarning

Typography

Marketing display for logged-out landing heroes; canvas scale for in-product UI.

Inter 400 body · 500 UI · 600 headings

Logged-out landing scale — larger than in-app canvas titles. Weight 400, tight tracking.

Create anything.

Generate, edit, and organize on an infinite canvas.

Create anything.

Marketing heroheading-display-hero--text-display-hero.lp2-hero h1 · .heading-display-hero

Built for creative teams

Marketing sectionheading-display-section--text-display-section.lp2-section-title · .heading-display-section

In-app canvas scale

Seven steps from 2rem page titles down to 11px panel labels. Pick by structural depth: page list → settings section → top bar name → inspector group → uppercase row label — not by how “important” the copy feels.

Largest to smallest above. Page title is a step above everything else; chrome and chat sit between section copy and inspector labels. Panel labels are 11px, uppercase, secondary ink.

SampleRenderedClassTokenWhere
My Boards2rem2remcv-heading-page--text-page-title.cv-list-title · .app-page-title
Board settings22px22pxapp-section-title--text-section-titleSettings / modal sections
Sharing & access15px15pxapp-subsection-title--text-subsection-titleNested settings blocks
Untitled board14px14pxcv-heading-chrome--text-chrome-title.cv-topbar-title
Next steps13px13pxcv-heading-chat--text-chat-heading.cv-cc-md h1–h6
Layout13px13pxcv-heading-section--text-panel-title.cv-inspector-section-title
Layers12px12pxcv-heading-panel-label--text-panel-label.cv-layers-heading-row · uppercase

Spacing

4px base grid. Prefer tokens over raw pixel values.

--space-14px
--space-28px
--space-312px
--space-416px
--space-520px
--space-624px
--space-832px
--space-1040px
--space-1248px
--space-1664px

Border radius

Radius is contextual: --radius-md for inspector fields, --radius-lg for top-bar controls, --radius-full for toolbars and selection pills.

--radius-nonenone
--radius-smsm (4px)
--radius-mdmd (6px)
--radius-lglg (8px)
--radius-xlxl (12px)
--radius-2xl2xl (16px)
--radius-fullfull

Shadows

--shadow-sm
--shadow-md
--shadow-lg
--shadow-xl

Materials & blur

Frosted chrome, modal scrims, and floating bars use tokenized blur values. Always pair -webkit-backdrop-filter with backdrop-filter for Safari.

Frosted chrome bar
Board title
Developer spec.app-glass-chrome · --surface-chrome · --blur-md
Modal scrim

Invite collaborators

Share this board with your team. The scrim blurs content behind it.

Developer spec.app-backdrop-scrim · --scrim-default · --blur-sm
Floating glass bar
Unsaved changes
Developer spec.app-glass-float · --blur-xl
When to skip blur

Heavy dialogs that re-render on every interaction should use a denser opaque scrim instead of full-screen blur (see canvas .cv-create-overlay).

Create organization

Dense fill, no backdrop-filter.

Developer spec.app-backdrop-scrim--dense · backdrop-filter: none

Motion

Hover the box — uses --duration-normal and --ease-default.

Buttons

Use .stdbutton for primary actions and .altbutton for secondary — compact density, one filled button per row.

Primary + secondary
Developer spec.stdbutton · .altbutton
Sizes
Developer spec.stdbuttonsmall · .stdbuttonbig
Disabled
Developer spec.stdbutton[disabled] · .stdbuttondisabled · .altbuttondisabled
Action row
Developer specone primary per row
Model badges
LG
Developer spec.model-badge--letzai

Canvas-specific chrome

Toolbar, inspector, and drawer controls use .cv-* classes where layout-specific.

Icon ghost
Developer spec.cv-icon-btn
Share actions
Developer spec.cv-share-btn · .cv-share-primary
Aspect pills
Developer spec.cv-section-aspect-pill
Primary CTA
Developer spec.cv-section-generate-btn
Floating toolbar
Developer spec.cv-toolbar · .cv-tool

Full canvas chrome catalog lives in styles/components/canvas.css.

Form controls

Text inputs use .app-input / .stdtextarea. Dropdowns use AppListSelect — not native <select>.

List select
Developer specAppListSelect · .app-dropdown
Property field
Developer spec.cv-prop-field

Deprecated legacy

Deprecated patterns — do not use in new UI. Prefer .app-input and AppListSelect.

Textarea
Developer spec.stdtextarea
Text input
Developer spec.app-input

Search & selection

Search fields, custom list selects, segmented controls, and toggle switches.

Search field
Developer spec.app-search-input
List select

Native <select> menus are OS-rendered. Use AppListSelect for on-brand dropdown panels.

Closed
Open
Developer specAppListSelect · .app-dropdown (not native <select>)
Segmented control
Developer spec.app-segmented
Toggle switch
Off
On
Developer spec.switch · .slider

Feedback & status

Alerts, status chips, and mentions from app-feedback.css.

Alert banners
Board published successfully.
Generation queue is busy — expect a short delay.
Upload failed. Check file size and try again.
Invite collaborators from the Share panel.
Developer spec.app-alert
Status chips
PublishedPendingFailedDraft
Developer spec.app-chip
Mention

Use @landscape-lora or @model in prompts.

Developer spec.app-mention

Loading & empty

Skeleton loaders and empty states from app-layout.css.

Skeleton
Developer spec.app-skeleton · --skeleton-base
Empty state

No boards yet

Create a board to start generating and organizing assets.

Developer specAppEmptyState · .app-empty-state

Modals & overlays

Modal content on --popupbg with scrim from .app-backdrop-scrim.

Modal shell

Delete board?

This removes the board for all collaborators. Generated assets stay in your library.

Developer spec.app-modal-shell · --popupbg

App screen

Composed hierarchy — how chrome, headings, and actions fit together on one screen.

Summer campaign

Generate assets

One primary action per row. Secondary actions stay ghost or bordered.

Aspect ratio

Body text

Paragraphs, captions, lists, links, and inline code across the app shell.

Primary body

LetzAI helps teams generate, edit, and organize creative assets on an infinite canvas. Default paragraph style at comfortable reading size.

Developer specp · --color · --text-base
Secondary

Supporting copy, metadata, and helper text use secondary ink via opacity.

Developer spec--text-secondary
Tertiary

Timestamps, placeholders, and de-emphasized labels.

Developer spec--text-tertiary
Disabled

Unavailable or inactive field hints.

Developer spec--disabledcolor
Caption

Caption text — notifications, footnotes, table meta.

Developer spec--text-xs
Links

Read the API documentation or use a ghost link button.

Developer spec.textlink · .ghost-link-btn
Inline code

Set data-theme="dark" on <html> to switch themes.

Developer speccode
Lists
  • Generate images from natural-language prompts
  • Edit and upscale existing assets
  • Organize work on shared boards
Blockquote
Hierarchy comes from opacity and weight, not product color accents in the app shell.
Developer spec--text-secondary

Layout & dividers

Hairline dividers, cards, and popup surfaces.

Horizontal divider

Content above


Content below

Developer spec.app-divider · --hairline
Vertical divider
Developer spec.app-divider-vertical
Content card

Summer campaign

Updated 2 hours ago · 12 assets

Developer spec.app-card
Popup surface

Dropdown or panel on popup surface.

Developer spec--popupbg · --shadow-md

Focus & accessibility

Keyboard focus uses --focus-ring — never hardcoded outline colors.

Focus ring

Tab to the control — uses box-shadow: var(--focus-ring).

Developer spec--focus-ring · .app-focus-target
Input focus
Developer spec.app-input:focus-visible

Elevation & z-index

Staggered stack — higher z-index layers sit above lower ones.

--z-base(1)
--z-dropdown(50)
--z-studio(150)
--z-header(190)
--z-modal(200)

Logos

LetzAI text logoText logo — header
LetzAI full logoFull logo — footer, OG

Maintain clear space equal to the height of the “L” mark. Do not stretch, recolor, or place on low-contrast backgrounds.

Do / Don't

Do

  • Add shared UI to styles/components/app-*.css
  • Use semantic tokens from styles/tokens/
  • Use canvas heading classes for in-app titles
  • Use .stdbutton / .altbutton for app-wide actions
  • Use AppListSelect for dropdown menus
  • Keep one filled primary per action row
  • Use opacity-based secondary text
  • Scope marketing purple to .lp2 only

Don't

  • Stack multiple .stdbutton fills in one row
  • Use global h1h6 in app UI
  • Use native <select> for product UI
  • Add purple accents to app shell
  • Add new patterns to styles.css
  • Hardcode hex in component CSS
  • Use flat #bbb for secondary text

Theme API

  • document.documentElement.setAttribute("data-theme", "light" | "dark")
  • Persisted in localStorage.theme (default: dark)
  • .loggedout / .auth-page use a dedicated dark chrome palette
  • The switch on this page is preview-only — it does not change your app-wide theme.

Token reference

Live values from the preview theme (Dark). Switch theme above to compare. Section links jump to where each token is documented.

TokenDark valueUsed by
--colorGlobal text
--text-secondarySecondary text
--text-tertiaryTertiary text
--bgPage shell
--verylightbgSubtle surface
--popupbgPanels / dropdowns
--surface-chrome.app-glass-chrome
--scrim-default.app-backdrop-scrim
--stdbuttonbg.stdbutton fill
--stdbuttoncolor.stdbutton text
--hairlineHairline border
--focus-ringFocus states
--color-successSuccess feedback
--color-errorError feedback
--text-display-heroLanding hero
--text-display-sectionLanding section titles
--text-page-titleCanvas page titles
--text-section-titleIn-app sections
--text-panel-titleInspector sections
--text-panel-labelLayers / panel labels
--text-subsection-titleNested settings blocks
--text-chrome-titleTop bar board name
--text-chat-headingCanvas chat headings
--control-font-sizeCanvas controls
--control-height-mdTop bar buttons
--control-height-smCompact controls
--blur-smModal scrims
--blur-mdSite header chrome
--blur-lgCanvas top bar
--blur-xlFloating bars
--backdrop-saturate-chromeHeader saturate
--backdrop-saturate-canvasCanvas top bar saturate
--scrim-denseDense overlay (no blur)
--radius-smSmall corners
--radius-mdInspector fields
--radius-lgTop-bar controls
--radius-fullToolbar, pills
--space-2Tight gap
--space-4Default gap
--space-8Section gap
--shadow-smSubtle elevation
--shadow-mdCards
--shadow-lgModals
--z-headerHeader
--z-modalModals
--duration-fastQuick transitions
--duration-normalTransitions
--ease-defaultEasing
--font-sansInter stack