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 h1–h6.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
Dropdowns AppListSelect / .app-dropdown — not native <select>
Legacy styles.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
--verylightbgSubtle surface
--surface-chromeFrosted chrome
--scrim-defaultModal scrim
--scrim-denseDense scrim (no blur)
--skeleton-baseSkeleton base
Interactive / chrome
--hairlineHairline border
--stdbuttonbgPrimary fill (= ink)
--stdbuttoncolorPrimary fill text
--accentcolorAccent (= ink)
--control-font-sizeCanvas control text
--control-height-mdCanvas control height
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.
Marketing hero heading-display-hero--text-display-hero.lp2-hero h1 · .heading-display-hero
Marketing section heading-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.
2rem · Page title My Boards
22px · Section title Board settings
15px · Subsection title Sharing & access
14px · Chrome title Untitled board
13px · Chat heading Next steps
13px · Inspector section Layout
12px · Panel label Layers
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.
Sample Rendered Class Token Where My Boards 2rem 2remcv-heading-page--text-page-title.cv-list-title · .app-page-title Board settings 22px 22pxapp-section-title--text-section-titleSettings / modal sections Sharing & access 15px 15pxapp-subsection-title--text-subsection-titleNested settings blocks Untitled board 14px 14pxcv-heading-chrome--text-chrome-title.cv-topbar-title Next steps 13px 13pxcv-heading-chat--text-chat-heading.cv-cc-md h1–h6 Layout 13px 13pxcv-heading-section--text-panel-title.cv-inspector-section-title Layers 12px 12pxcv-heading-panel-label--text-panel-label.cv-layers-heading-row · uppercase
Spacing 4px base grid. Prefer tokens over raw pixel values.
Border radius Radius is contextual: --radius-md for inspector fields, --radius-lg for top-bar controls, --radius-full for toolbars and selection pills.
Materials & blur Frosted chrome, modal scrims, and floating bars use tokenized blur values. Always pair -webkit-backdrop-filter with backdrop-filter for Safari.
Developer spec .app-glass-chrome · --surface-chrome · --blur-mdModal scrim
Invite collaborators
Share this board with your team. The scrim blurs content behind it.
Cancel Send invite
Developer spec .app-backdrop-scrim · --scrim-default · --blur-smFloating glass bar
Unsaved changes Discard Save
Developer spec .app-glass-float · --blur-xlWhen 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: noneMotion Hover the box — uses --duration-normal and --ease-default.
Search & selection Search fields, custom list selects, segmented controls, and toggle switches.
Developer spec .app-search-inputList select Native <select> menus are OS-rendered. Use AppListSelect for on-brand dropdown panels.
Developer spec AppListSelect · .app-dropdown (not native <select>)Developer spec .app-segmentedDeveloper spec .switch · .sliderFeedback & 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-alertStatus chips Published Pending Failed Draft
Developer spec .app-chipMention Use @landscape-lora or @model in prompts.
Developer spec .app-mentionLoading & empty Skeleton loaders and empty states from app-layout.css.
Developer spec .app-skeleton · --skeleton-baseEmpty state No boards yet Create a board to start generating and organizing assets.
New board
Developer spec AppEmptyState · .app-empty-stateModals & 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.
Cancel Delete
Developer spec .app-modal-shell · --popupbgApp screen Composed hierarchy — how chrome, headings, and actions fit together on one screen.
Summer campaign Import Share
Generate assets One primary action per row. Secondary actions stay ghost or bordered.
Aspect ratio 1:1 16:9 9:16
16:9
Generate 4 images 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 spec p · --color · --text-baseSecondary Supporting copy, metadata, and helper text use secondary ink via opacity.
Developer spec --text-secondaryTertiary Timestamps, placeholders, and de-emphasized labels.
Developer spec --text-tertiaryDisabled Unavailable or inactive field hints.
Developer spec --disabledcolorCaption Caption text — notifications, footnotes, table meta.
Developer spec --text-xsDeveloper spec .textlink · .ghost-link-btnInline code Set data-theme="dark" on <html> to switch themes.
Developer spec codeLists 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-secondaryLayout & dividers Hairline dividers, cards, and popup surfaces.
Horizontal divider Content above
Content below
Developer spec .app-divider · --hairlineDeveloper spec .app-divider-verticalContent card Summer campaign
Updated 2 hours ago · 12 assets
Developer spec .app-cardPopup surface Dropdown or panel on popup surface.
Developer spec --popupbg · --shadow-mdFocus & accessibility Keyboard focus uses --focus-ring — never hardcoded outline colors.
Focus ring Tab to the control — uses box-shadow: var(--focus-ring).
Focus me Developer spec --focus-ring · .app-focus-targetDeveloper spec .app-input:focus-visibleElevation & 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 Text logo — header Full 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 ✓ DoAdd 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'tStack multiple .stdbutton fills in one row Use global h1–h6 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 paletteThe 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.