Lovable Design System
Overview
Lovable's visual identity centers on a striking hero treatment—a vibrant gradient canvas that transitions from coral-pink through magenta to deep blue—creating an immediate sense of creative energy and technological possibility. Against this expressive backdrop, the design deploys surgical restraint elsewhere: near-black ink text in the proprietary Camera Plain Variable typeface, a single high-contrast black primary button, and a predominantly white/neutral surface language. This juxtaposition of exuberant gradient moments with Swiss-grade typographic precision signals a product that is simultaneously playful and technically rigorous—an AI builder that takes your ideas seriously while making creation feel effortless.
The brand voltage concentrates in two specific surfaces: the hero band's gradient wash (the only place color explodes outward) and the deep-blue {colors.primary} accent reserved for interactive links and semantic emphasis. Everything else operates in a disciplined monochrome-plus-one-accent mode. The primary call-to-action ({component.button-primary}) deliberately rejects the gradient vocabulary, instead using an almost-black solid (rgba(0, 0, 0, 0.88)) that reads as authoritative and final—a "Commencer" button that feels decisive rather than decorative.
Typography defines this system's character more than any other dimension. Camera Plain Variable, a proprietary geometric sans-serif, carries all text from 48px display headlines down to 14px button labels. The headline weight sits at 600—present but never aggressive—with a slight negative letter-spacing (-1.92px at 48px) that tightens the letterforms for a modern, compact feel. Body text remains at weight 400, trusting size and color contrast (not weight) to establish hierarchy. This creates a quiet confidence: the type doesn't shout; it speaks clearly.
Shape language favors generous rounding. Input containers use {rounded.xl} (16px), buttons sit at {rounded.DEFAULT} (8px), and circular icon triggers go fully round. The overall impression is approachable and soft—nothing sharp, nothing threatening. Combined with the multi-layered shadow system that lifts cards and inputs subtly off their backgrounds, the tactile quality feels premium without being ostentatious.
Key Characteristics
- Hero canvas uses a signature pink-to-blue gradient (not captured as a single token—implemented via CSS gradient)
- Primary CTA is near-black (
rgba(0, 0, 0, 0.88)) with white text ({colors.on-dark}), not the brand blue - All text uses Camera Plain Variable at weights 400–600, never exceeding 600
- Display headlines employ negative letter-spacing (up to -1.92px at 48px) for tightened rhythm
- Border radius scales from 6px (subtle) to 24px (cards) to fully round (icon buttons)
- Shadow system uses 5+ layered shadows for elevated surfaces, creating soft depth
- Spacing operates on an 80px vertical rhythm for sections, with 2–40px granular tokens
- Color palette is intentionally restricted: black/white/gray + one primary blue + gradient hero
- Input fields are white pills floating above the gradient with pronounced focus elevation
Colors
Brand & Accent
- Primary (
{colors.primary}— #01006b): Deep navy blue used for semantic links, interactive accents, and active states. Appears sparingly—only where explicit brand reinforcement is needed. - Primary Active (
{colors.primary-active}— #000552): Darker navy for pressed/active states on primary-colored elements. - Accent (
{colors.accent}— #1c52f1): Brighter blue appearing in specific UI chrome elements and link hover states where higher visibility is required.
Surface
- Canvas (
{colors.canvas}— #010000): Near-black base—technically the deepest surface, though visually the hero overrides this with its gradient. Used as the page background token. - Surface (
{colors.surface}— #ffffff): Pure white. The dominant surface for cards, nav, modals, and content areas below the hero. - Surface Soft (
{colors.surface-soft}— #fcfbf8): Warm off-white with a hint of cream. Used for subtle container differentiation and alternating band backgrounds. - Surface Warm (
{colors.surface-warm}— #f9f8f5): Slightly warmer neutral for nested containers or secondary card backgrounds. - Surface Neutral (
{colors.surface-neutral}— #f5f4f0): The coolest/warmest gray in the surface family. Reserved for disabled states, code blocks, or deeply recessed areas.
Text
- Ink (
{colors.ink}— #000000): Pure black for maximum-contrast elements: logo wordmark, nav links, primary headlines. - Body (
{colors.body}— #1c1c1c): Near-black (RGB 28,28,28). The workhorse text color for headlines, paragraphs, and prominent UI labels. Provides excellent readability without the harshness of true black. - Muted (
{colors.muted}— #616161): Medium gray for secondary text: subheadlines, descriptions, placeholder text in inputs. - Muted Soft (
{colors.muted-soft}— #989898): Light gray for tertiary/disabled text: captions, timestamps, hints, decorative labels. - On Primary (
{colors.on-primary}— #ffffff): White text on the rare primary-blue backgrounds. High contrast against#01006b. - On Dark (
{colors.on-dark}— #faf9f4): Warm white for text sitting on the near-black primary button. Slightly warmer than pure white to reduce glare.
Hairlines & Borders
- Hairline (
{colors.hairline}— rgba(0, 0, 0, 0.08)): Very subtle divider. Used for faint separators between content zones or as the lightest border treatment. - Border Strong (
{colors.border-strong}— rgba(0, 0, 0, 0.15)): Medium-opacity border for input fields, card outlines when needed, and defined containment boundaries. - Border Input (
{colors.border-input}— rgba(220, 220, 215, 0.4)): Warm-tinted low-contrast border specifically for input fields. Has a slight warmth to harmonize with the surface-soft tokens.
Semantic
- Success (
{colors.success}— #006400): Dark green for confirmation states, success messages, and positive indicators. - Link (
{colors.link}— #1c52f1): Bright blue matching the accent. Used for inline text links and clickable references outside of button contexts. - Link Active (
{colors.link-active}— #01006b): Deepens to primary navy on hover/active/focus for link interaction feedback.
Typography
Font Family
Lovable uses Camera Plain Variable exclusively—a proprietary variable font covering weights 100–900 in a single file. The font is a geometric sans-serif with rationalized proportions, slightly squared-off curves, and excellent legibility at both display (48px+) and micro (14px) sizes. The fallback stack (ui-sans-serif, system-ui, sans-serif) ensures graceful degradation on systems where Camera isn't loaded. An italic variant ("Camera Plain Variable Italic") exists at weight 400 for emphasis within body text, though it appears rarely in the marketing surface.
A secondary font, Roboto Mono Variable, is declared in the font-face list (weights 100–700) but does not appear in the extracted marketing-page typography. It is likely reserved for code snippets, terminal previews, or developer-facing documentation surfaces not visible in this screenshot.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
| {typography.display-xl} | 56px | 600 | 1.1 | -0.02em | Hero-scale headlines (larger viewports, future use) |
| {typography.display-lg} | 18px | 400 | 1.56 | 0 | Large body / feature intros |
| {typography.title-md} | 48px | 600 | 1.1 | -0.04em | Primary hero headline |
| {typography.title-sm} | 16px | 600 | 1.5 | 0 | Section titles, card headers |
| {typography.body-md} | 18px | 400 | 1.33 | 0 | Body copy, subheadlines, input text |
| {typography.body-sm} | 15px | 400 | 1.6 | 0 | Nav links, secondary body text |
| {typography.caption} | 14px | 400 | 1.43 | 0 | Button labels, metadata, small UI text |
| {typography.button} | 14px | 400 | 1.43 | 0 | Button text (identical to caption) |
| {typography.label-md} | 15px | 400 | 1.6 | 0 | Navigation menu items, label text |
Principles
The typography system trusts size and color over weight to create hierarchy. Notice that body text (18px/400) shares the same weight as button text (14px/400) and nav links (15px/400)—the only weight increase occurs at 600 for headlines (title-md, title-sm, display-xl). This means a 48px headline at 600 feels dramatically larger than 18px body text at 400, without needing a 700/800 weight that would feel aggressive or cheap. The result is a refined, editorial voice that feels closer to a design magazine than a startup landing page.
Letter-spacing manipulation is strategic and minimal. Only the largest display sizes receive negative tracking (-0.02em to -0.04em), tightening the letterforms so they read as cohesive visual blocks rather than strings of individual characters. All text below 24px uses normal (0) letter-spacing, preserving the font's native spacing which has been professionally optimized.
Color does significant heavy lifting in the hierarchy. The headline uses {colors.body} (#1c1c1c) while the subheadline drops to {colors.muted} (#616161)—a 40% lightness difference that creates clear order without any size or weight change (both are 18px/400 in many layouts). This is a mature typographic technique: letting value contrast carry what boldness refuses to.
Note on Font Substitutes
Camera Plain Variable is a proprietary font not available on Google Fonts. For open-source reimplementation, the closest visual match is DM Sans (Google Fonts), which shares the geometric sans-serif construction, similar x-height, and variable weight support. Define the substitution as:
:root {
--font-family-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif;
}
If Camera Plain Variable becomes unavailable, DM Sans at weight 500 approximates the 400 weight of Camera (which sits visually heavier than a typical 400 due to its construction). For the 600-weight headlines, DM Sans 600 maps directly. Avoid substituting with Inter (too neutral/humanist) or SF Pro (system-bound, different character).
Layout
Spacing System
-
Base unit: 2px (with 4px, 6px, 8px as practical working increments).
-
Tokens:
{spacing.xxs}(2px): Micro-adjustments, tight icon gaps, focus ring offsets.{spacing.xs}(4px): Icon-text gaps, inner button padding halving.{spacing.sm}(6px): Standard small gap, button internal padding, nav item spacing.{spacing.md}(8px): Input padding, icon button hit area expansion, card inner gutters.{spacing.lg}(10px): Button horizontal padding, form element spacing.{spacing.xl}(12px): Section horizontal padding at mobile, card padding small.{spacing.2xl}(16px): Card padding standard, section side margins.{spacing.3xl}(24px): Card padding large, element stacking gaps.{spacing.4xl}(28px): Between block spacing in dense layouts.{spacing.5xl}(32px): Subsection separators, feature grid gaps.{spacing.6xl}(40px): Major vertical rhythm, before/after hero content.{spacing.section}(80px): Full section-to-section vertical padding.
-
Section padding (vertical):
{spacing.section}(80px) — used between hero and content sections, and between subsequent major bands. -
Card internal padding:
{spacing.3xl}(24px) for standard{component.card},{spacing.xl}(12px) for compact{component.card-surface-soft}. -
Gutters: Page-level horizontal gutter is
{spacing.xl}(12px) on mobile scaling to{spacing.2xl}(16px)+ on desktop. Inner container max-width is 1440px.
Grid & Container
- Max content width: 1440px (extracted from
mainandsectioncontainer widths). Content is centered within viewport beyond this width. - Density choice: Editorial/marketing density—not marketplace-dense (no 4-column product grids visible) nor app-dense (no dashboards). Generous whitespace dominates, with the hero occupying most of the initial viewport.
- Desktop grid behavior: The screenshot shows a centered single-column hero layout (text + input stacked vertically centered). At wider breakpoints, this likely evolves to a two-column layout with text left and illustration/preview right (inferred from the horizontal space available).
- Hero column split: Current visible state is single-column centered. The input field spans approximately 560–640px wide, suggesting a constrained content column (~640px) within the 1440px container for readable line lengths.
Whitespace Philosophy
Lovable embraces editorial-airy whitespace. The hero section breathes with 80px+ vertical padding on all sides, and the input field floats with substantial clearance around it. This is not a cramped SaaS pricing page—it's a brand statement that uses empty space as a design element. The gradient background demands room to shine; crowding it would diminish the effect. Below the fold (inferred), the pattern likely shifts slightly denser for feature grids, but never approaches marketplace density.
Header Architecture
|<-------------------------------- 1440px max -------------------------------->|
|[Logo] [Solutions v] [Ressources v] [Communauté] [Tarifs] [Sécurité] [Se connecter] [Commencer]|
| |
|---------------------------------------------------------------------------------------|
^-- flush left ^-- center-left nav cluster ^-- flush right CTAs
- Height: 64px (
{component.top-nav}) - Logo: Left-aligned, "Lovable" wordmark with gradient/party-popper icon
- Nav items: Horizontal row with chevron indicators on dropdowns (Solutions, Ressources)
- Right rail: Secondary button (ghost) → Primary button (filled black)
- Background:
{colors.surface}(white) - No visible bottom border/shadow on nav in default state (clean float)
Hero Section
|<---------------------------- centered column ------------------------------>|
| |
| |
| Créez quelque chose avec Lovable |
| Donnez vie à un nouveau produit, à un outil interne |
| ou à toute une entreprise. |
| |
| [+] Demande... [Créer v] [mic] |
| |
| |
|<------------------------ gradient canvas behind --------------------------->|
- Layout: Single centered column, vertically centered in viewport
- Headline:
{typography.title-md}(48px/600) in{colors.body} - Subheadline:
{typography.body-md}(18px/400) in{colors.muted} - Input container: White pill (
{component.hero-input-container}) with{rounded.xl}, shadow-elevated, containing:- Left: Plus icon circle button (
{component.hero-input-addon-left}) - Center: Text input area (
{component.hero-input}) - Right: "Créer" dropdown trigger + microphone icon
- Left: Plus icon circle button (
- Background: Pink→magenta→blue gradient (CSS gradient, not a flat token)
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| 0 (Flat) | No shadow, no border | Nav bar, flat band backgrounds, footer |
| 1 (Hairline) | inset 0 0 0 1px rgba(255,255,255,0.1) | Subtle inner highlight on dark surfaces |
| 2 (Soft raise) | {extensions.shadows.sm} — 1px offset + 1px border | Buttons at rest, subtle card lift indication |
| 3 (Float) | {extensions.shadows.md} — Multi-layer 4-8px spread | Cards, dropdown panels, input containers at rest |
| 4 (Elevated) | {extensions.shadows.lg} — Wide 20-30px spread, 5 layers | Hero input on focus, modal dialogs, prominent popovers |
| 5 (Focus ring) | {extensions.shadows.input-focus} — Custom dark-tinted wide shadow | Input focus state, keyboard-navigable element focus |
The depth philosophy here is layered soft realism. Rather than a single hard shadow, elevated elements receive 3–5 layered shadows at different spreads and opacities, creating a natural falloff that mimics real-world object elevation. Notice that the shadows use slightly warm grays (rgba(95, 95, 93, ...) and rgba(118, 118, 118, ...)) rather than pure black, which keeps them feeling organic and integrated with the warm surface tints.
Color-block depth (the gradient hero) coexists peacefully with shadow-based depth (the floating input). The gradient provides atmospheric/background depth, while shadows provide foreground/object depth. They don't compete—they operate in different visual layers.
Decorative Depth
The hero gradient is the defining decorative depth element. While not expressible as a single hex token, it is implemented as a multi-stop CSS gradient transitioning from coral/pink (lower-left) through magenta (center) to blue (upper-right). This gradient is likely implemented as a background-image on the hero section's container, with sufficient blur/size to appear as a soft wash rather than hard color bands. Future implementations should preserve this as a CSS custom property or Tailwind arbitrary value, not flatten it to a JPEG.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
| {rounded.sm} | 6px | Small inner elements, subtle corner softening |
| {rounded.DEFAULT} | 8px | Standard radius — buttons, toggles, small badges |
| {rounded.md} | 12px | Compact cards, panel corners, toast notifications |
| {rounded.lg} | 16px | Standard cards, input containers (inner), image frames |
| {rounded.xl} | 24px | Hero input container (outer), feature cards, prominent pods |
| {rounded.pill} | 9999px | Circular icon buttons, avatar placeholders, pill tags |
| {rounded.full} | 9999px | Alias for pill — fully rounded (circle/oval) |
The shape progression tells a story: small UI controls get gentle 8px rounds (friendly but not blobby), cards get 16–24px (clearly "app-like" and modern), and iconic/circular elements go fully round. There's no sharp-corner (0px) element in the main UI except the nav bar container and skip-link positioning—everything touchable has some rounding.
Components
No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the
components:frontmatter (e.g.{component.button-primary-active},{component.text-input-focus}); add hover styling at implementation time per your stack's conventions.
Buttons
{component.button-primary} — The primary call-to-action button seen as "Commencer" in the top nav. Background is near-black (rgba(0, 0, 0, 0.88)), text is warm white ({colors.on-dark}), rendered in {typography.button} (14px/400) with {rounded.DEFAULT} (8px) corners and {spacing.sm} × {spacing.lg} padding (6px vertical, 10px horizontal). Height is fixed at 32px. Box-shadow is none at rest—it relies on its solid color for presence. This button feels decisive and final; it's where users commit.
{component.button-secondary} — The ghost/outline-adjacent button seen as "Se connecter". Transparent background, {colors.ink} text, identical typography and dimensions to primary. On hover/focus it likely gains a subtle background tint or underline (implement per stack). Used for lower-commitment actions: sign in, learn more, secondary paths.
{component.button-icon} — Square icon-only button (32×32px) with transparent background, {colors.ink} icon color, 8px padding, and zero border-radius. Used for the close/dialog-trigger button visible in the nav area. Icons inside render at 16px ([&_svg[data-default-size]]:size-4 in the class list).
Navigation
{component.top-nav} — The persistent header bar spanning full viewport width at 64px height. White background ({colors.surface}), ink-colored text ({colors.ink}), {typography.label-md} (15px) for menu items. Contains the logo left, navigation center-left, and CTAs right. No visible shadow or border at rest—it floats cleanly atop the hero gradient.
{component.nav-link} — Individual navigation menu item (e.g., "Solutions", "Ressources", "Communauté"). Transparent background, ink text, 4px vertical × 6px horizontal padding. Dropdown indicators (chevrons) accompany items with sub-menus. Text transitions to 80% opacity on hover/popup-open (text-marketing-foreground/80).
{component.nav-link-hover} — Hover/active state for nav links. Text color reduces to rgba(0, 0, 0, 0.8) (80% ink). No background change—color dimming alone signals interaction.
Cards & Containers
{component.card} — Standard content card. White background ({colors.surface}), body text color ({colors.body}), {typography.body-md}, {rounded.lg} (16px) corners, {spacing.3xl} (24px) internal padding. Receives {extensions.shadows.md} elevation when floated. Used for feature descriptions, testimonial blocks, or content pods below the hero.
{component.card-elevated} — Prominent variant with {rounded.xl} (24px) corners and {extensions.shadows.lg} elevation. Same padding and typography as standard card. Reserved for hero-adjacent elements or featured content that needs to "pop" more than a standard card.
{component.card-surface-soft} — Subtle background variant using {colors.surface-soft} (warm off-white) instead of pure white. {rounded.md} (12px) corners, tighter {spacing.xl} (12px) padding. Used for nested content areas or secondary information panels where visual hierarchy needs to de-emphasize the container.
{component.hero-band} — The full-width hero section container. Transparent background (allows gradient to show through), ink text, {typography.title-md} for its headline child. Padding is {spacing.section} (80px) vertically and {spacing.xl} horizontally. This is a structural/layout component more than a visual skin.
Inputs & Forms
{component.hero-input-container} — The outer pill-shaped container wrapping the hero search/input area. White background ({colors.surface}), {rounded.xl} (16px), 8px padding internally, {typography.body-md} text styling. Carries {extensions.shadows.lg} elevation (the wide multi-layer shadow) making it float prominently above the gradient. This is the visual star of the hero—a tangible "place to type" that invites interaction.
{component.hero-input} — The actual text input field inside the container. Transparent background (inherits white from parent), {colors.ink} text, {typography.body-md}, {rounded.sm} (6px) for any internal focus ring, 8px padding. Placeholder text uses {colors.muted}. On focus, the container elevates further to {extensions.shadows.input-focus} while the input itself may show a subtle ring.
{component.hero-input-focus} — Focus state for the inner input. Maintains transparency and typography but may gain a subtle outline or background shift. The primary focus visual is actually the container's shadow upgrade.
{component.hero-input-addon-left} — The circular "+" button on the left side of the input. Transparent background, muted text/icon color ({colors.muted}), {rounded.pill} (fully circular), 28×28px size. Likely triggers an attachment or option menu.
{component.hero-input-addon-right} — Right-side addons including the "Créer" dropdown trigger and microphone icon. Transparent background, muted text ({typography.caption}, 14px), 4px padding. The "Créer" text includes a chevron indicating a dropdown menu for selecting creation mode.
Typography Components
{component.hero-headline} — The main "Créez quelque chose avec Lovable" heading. Transparent background, {colors.body} text (#1c1c1c), {typography.title-md} (48px/600, -1.92px letter-spacing). This is the most visually dominant text element on the page.
{component.hero-subheadline} — The descriptive text beneath the headline. Transparent background, {colors.muted} text (#616161), {typography.body-md} (18px/400). Provides context without competing for attention.
Structural Components
{component.footer} — Page footer (inferred position, partially visible in structure). White background, muted text color ({colors.muted}), {typography.caption} (14px) for legal/nav links, generous {spacing.6xl} (40px) vertical padding. Likely contains copyright, links, and trust markers.
{component.skip-link} — Accessibility skip-navigation link. Fixed positioned top-left, near-black background, warm-white text, {typography.button} styling, {rounded.sm} (6px), 8px×16px padding. Hidden until focused (.hidden min-[430px]:inline-flex pattern).
Do's and Don'ts
Do
- Do use
{colors.body}(#1c1c1c) for all headlines and primary body text—never pure{colors.ink}(#000000) except for the logo and highest-contrast nav elements. - Do apply
{typography.title-md}(48px/600) with its -1.92px letter-spacing to the hero headline; this tightening is intentional and part of the brand's modern feel. - Do give the hero input container
{rounded.xl}(16px) corners and{extensions.shadows.lg}elevation—it should feel like it's floating above the gradient. - Do reserve
{colors.primary}(#01006b) for links and semantic accents; the primary CTA button uses near-black, not blue. - Do use
{rounded.DEFAULT}(8px) for all standard buttons—this is the system's "default roundness" and should feel ubiquitous. - Do maintain 80px (
{spacing.section}) vertical rhythm between major sections; the airy feel depends on this generosity. - Do apply the multi-layer shadow pattern (
{extensions.shadows.md}or.lg) to any elevated card rather than a single hard shadow. - Do keep button font-weight at 400 (
{typography.button}) even for primary CTAs—the near-black background provides enough contrast without needing bolder text. - Do use
{colors.surface-soft}(#fcfbf8) for alternating section backgrounds when you need subtle separation without borders. - Do ensure the gradient hero remains the only colorful moment on the page; everything else should live in the neutral + blue accent world.
Don't
- Don't use
{colors.primary}(#01006b) as the primary button background—the CTA is intentionally near-black (rgba(0, 0, 0, 0.88)). - Don't exceed font-weight 600 anywhere in the system; the heaviest weight (
{typography.title-md}at 600) is reserved for headlines only. - Don't add visible borders to the nav bar—it floats cleanly with no shadow or bottom-border at rest.
- Don't use sharp corners (0px radius) on any interactive element; the minimum is
{rounded.sm}(6px). - Don't substitute
{colors.link}(#1c52f1) for{colors.primary}(#01006b)—they serve different roles (bright link vs. deep brand). - Don't compress section vertical padding below
{spacing.section}(80px) in the hero and first content band; this breathing room is foundational to the aesthetic. - Don't apply gradients to buttons, cards, or any element besides the hero background—the gradient is a singular signature moment.
- Don't use font sizes below 14px (
{typography.caption}/{typography.button}) for any user-facing text; the system doesn't go smaller. - Don't add box-shadows to
{component.button-primary}at rest—its solidity comes from the opaque background, not elevation. - Don't mix font families—100% of text uses Camera Plain Variable; Roboto Mono is for code only.
Motion & Animation
Transition Tokens
/* Core UI transitions */
--transition-colors: color 0.15s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--transform-base: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), translate 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--opacity-fast: opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);
/* Elevated/slow transitions */
--transition-elevated: background 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-modal: background-color 0.3s ease-out, border-color 0.8s ease-out, backdrop-filter 0.3s ease-out, box-shadow 0.3s ease-out;
/* Micro-interactions */
--transform-quick: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1), translate 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--opacity-snappy: opacity 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
Keyframe Animations
shimmer-gradient— Shimmer sweep effect for loading skeletons or highlighted badgesgradient— General gradient animation (likely for the hero background or accent elements)heartbeat/heartbeat-strong— Pulsing heart icon animation (likely for "like" or favorite interactions)heart-shimmer-sweep— Combined heart pulse with shimmer overlayshake— Horizontal shake for error/validation feedbackanimate-blink— Cursor/text caret blinkinggradient-sweep/gradient-sweep-flat— Gradient position animation for moving color washesmessage-highlight— New message or notification flashenter/exit— Modal or panel entrance/exit transitionsspin— Loading spinner rotationpulse— Subtle pulsing for attention-drawing elementsbounce— Bounce feedback for scroll-to-top or action confirmationgradient-badge-pop/gradient-badge-pop-tilt— Badge appearance animation with scale + optional tiltcaret-blink— Input cursor blinkshine/shine-w1— Highlight/sheen sweep across surfaces (premium feel)
Interaction Patterns
- Input focus elevation: The hero input container upgrades from
{extensions.shadows.lg}to{extensions.shadows.input-focus}on focus, with a 0.3scubic-bezier(0.4, 0, 0.2, 1)transition on bothbackgroundandbox-shadow. - Nav link dimming: Navigation menu items fade to 80% opacity on hover or when their popup is open, using the 0.15s color transition.
- Modal/panel reveal: Overlay panels (dropdowns, dialogs) animate in with background-color, border-color, backdrop-filter, and box-shadow all transitioning over 0.3s ease-out.
- Button micro-interactions: Buttons use 0.15s-0.2s transforms for press/tap feedback (scale down slightly).
- Scroll-triggered reveals: While not explicitly in the transition data, the presence of
enter/exitkeyframes suggests content blocks animate in on scroll (fade-up or fade-in). - Shimmer loading states: The
shimmer-gradientandshineanimations indicate skeleton loaders with a sweeping highlight during async content fetches. - Icon button scale: Icon-only buttons (
{component.button-icon}) likely scale slightly (0.95–1.0) on press via the quick transform transition.
Imagery Style
- Hero imagery: The hero currently uses a CSS gradient wash (pink→magenta→blue) rather than photography or illustration. This gradient is the primary "visual" — abstract, atmospheric, and branded.
- Illustration style: Not visible in this screenshot, but the product nature (AI app builder) suggests 3D-rendered app mockups or isometric device previews may appear below the fold in the full page.
- Photography: Absent from the visible hero section. If present elsewhere, it would likely follow a clean, high-key studio aesthetic matching the white-surface design language.
- Gradient treatment: The hero gradient is soft-edged (large blur radius), creating a watercolor-wash effect rather than hard color bands. It occupies the full viewport behind the centered content.
- Decorative vs. functional: The gradient is purely decorative/atmospheric — it doesn't convey information, just mood. All functional UI (input, buttons, text) sits in solid-color containers above it.
- Color temperature: The gradient spans warm (coral/pink) to cool (blue), creating visual tension and dynamism. This duality mirrors the brand's positioning (creative warmth + technical rigor).
- Image geometry: Not applicable for the gradient, but any future photography/illustration would likely use
{rounded.lg}(16px) or{rounded.xl}(24px) corners consistent with the card system.
Icon System
- Library: Custom SVG icons (no detected Lucide, Heroicons, Material, or Bootstrap class patterns). Icons are inline SVGs with
data-default-sizeattributes for consistent sizing. - Specific icons observed:
- Party-popper / confetti icon (logo mark, multicolored — pink/yellow/blue)
- Chevron-down (nav dropdown indicators, "Créer" trigger)
- Plus-circle (left addon in hero input)
- Microphone (right addon in hero input)
- Close/X (icon button inferred from dialog-trigger classes)
- Treatment: Stroke-based icons (not filled), rendered in
currentColorfor theme alignment. Size is controlled via[&_svg[data-default-size]]:size-4(16px) within buttons, scaling up in standalone contexts. - Alignment: Icons center vertically with adjacent text using flexbox (
flex items-center). Gap between icon and text is{spacing.xs}(4px) or{spacing.xxs}(2px) depending on context. - Color: Inherit from parent text color (usually
{colors.ink}or{colors.muted}). The logo icon is multicolored (brand gradient) and does not followcurrentColor.
Recommended Frontend Stack
- Framework: Next.js (App Router) or Astro — SSR-friendly, optimized for marketing pages
- Styling: Tailwind CSS v4 (confirmed by utility class patterns: `rounded-2`, `typestyle-control-sm`, `btn-chassis`)
- Fonts: Self-hosted "Camera Plain Variable" WOFF2 (already served from `/assets/`)
- Animation: Tailwind-built-in transitions + CSS keyframes (defined in stylesheet)
- Icons: Custom SVG components (inline, with `data-default-size` attribute pattern)
- Component lib: Custom components (no shadcn/Radix detected — bespoke button/card primitives)
Responsive Behavior
Breakpoints
| Name | Width | Key Changes | |---|---|---| | Mobile | < 430px | Skip-link hidden, "Se connecter" button hidden, condensed nav, stacked hero | | Tablet | 430px – 1024px | Full nav visible, hero remains single-column, reduced section padding | | Desktop | 1024px – 1440px | Full layout, 1440px max-content container, optimal spacing tokens | | Wide | > 1440px | Content centers with increasing side margins, no layout stretch |
Touch Targets
{component.button-primary}: 32px height × ~80+px width (padding 6px×10px + text). Fails WCAG AAA (44px minimum) but common in desktop-first navs. Consider increasing to 40px height for mobile.{component.button-secondary}: Identical 32px height. Same consideration as primary.{component.hero-input-container}: Approximately 56–64px total height (padding + input line-height). Passes WCAG AAA comfortably. Excellent touch target.{component.button-icon}: 32×32px (8px padding × 4 sides on invisible boundary). Fails AAA, marginal for AA. Recommend 40×40px minimum.{component.hero-input-addon-left}: 28×28px circular. Fails both AA and AAA. Should expand to 44px for mobile usability.
Collapsing Strategy
- Navigation: At < 430px, the "Se connecter" secondary button hides (
hidden min-[430px]:inline-flex), leaving only "Commencer". The full nav likely collapses to a hamburger menu below tablet (standard pattern, though hamburger not visible in this screenshot). - Hero layout: Remains single-column (centered stack) across all visible breakpoints. At wide desktop, a two-column variant (text left, illustration right) may activate but isn't visible here.
- Input container: Maintains full width (constrained to ~640px max) on mobile, with internal addons potentially collapsing or reordering.
- Section padding:
{spacing.section}(80px) likely reduces to{spacing.6xl}(40px) or{spacing.5xl}(32px) on mobile to avoid excessive scrolling. - Type scale:
{typography.title-md}(48px) likely steps down to 36px or 32px on mobile to prevent overflow.{typography.body-md}(18px) may reduce to 16px.
Image Behavior
- Hero gradient: The CSS gradient background scales fluidly with viewport — no image to resize, just
background-size: coverbehavior. - Future illustrations: Any app mockups or device previews added below the hero should use
aspect-ratiocontainers, responsive<picture>elements, and{rounded.xl}corners that maintain proportion across breakpoints. - Logo: The party-popper icon + "Lovable" wordmark likely reduces in overall size on mobile (font-size or scale transform) while maintaining legibility.
Iteration Guide
-
Set up the font first. Self-host
CameraPlainVariable-c48bd243-BhPypTEq.woff2and define@font-facewith weight range 100–900. Set--font-family-sans: "Camera Plain Variable", ui-sans-serif, system-ui, sans-serifas your CSS variable. Every typography token references this family. -
Build the hero gradient. Implement the pink→magenta→blue gradient as a CSS
background-imageon the hero section usingradial-gradientor multiplelinear-gradientlayers with large blur/radius. This is not a token — it's a one-time CSS implementation. Ensure it sits behind the centered content withz-indexlayering. -
Implement the input container as the hero's centerpiece. Use
{component.hero-input-container}specs: white bg,{rounded.xl}(16px),{extensions.shadows.lg}elevation, 640px max-width, centered. Inside, build the three-zone layout (left addon + input + right addons) using flexbox with appropriate gaps. -
Reserve
{colors.primary}strictly for links. When building navigation, inline links, or accent text, use#01006b. When building the primary CTA button, usergba(0, 0, 0, 0.88)— this distinction is critical to the brand's visual logic. -
Apply the multi-layer shadow pattern. Never use a single
box-shadowshorthand for elevated elements. Copy the full comma-separated layer string from{extensions.shadows.md},.lg, or.input-focusexactly. These 5-layer shadows are a signature detail. -
Use
{typography.title-md}for the hero headline with its letter-spacing. The 48px/600/-1.92px combo is non-negotiable for brand recognition. Omitting the negative tracking will make the headline feel generic. -
Follow the 80px section rhythm. Set
padding-topandpadding-bottomto{spacing.section}(80px) on the hero and each major content band. If the design feels "too spacious," resist the urge to compress this — the airiness is intentional. -
Map every component in the frontmatter to a React/Vue/Svelte component. Each entry (
button-primary,hero-input-container,card-elevated) should become a reusable component accepting props forbackgroundColor,textColor, etc., defaulted to the token values. -
Add state variants as separate component entries or props. Don't nest
-hoverand-focusstyles inside the default component. CreateButtonPrimaryHoveror pass avariant="hover"prop. The spec documents Default and Active/Focus as distinct entries for a reason. -
Run the linter. After implementing, run
npx @google/design.md lint DESIGN.mdto catch broken token references ({colors.nonexistent}), orphaned tokens (defined but never referenced), and contrast-ratio warnings (especially{colors.primary}on{colors.surface}).
Font Setup for Reimplementation:
Since Camera Plain Variable is proprietary, use DM Sans from Google Fonts as the nearest substitute:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&display=swap" rel="stylesheet">
CSS variable definition:
:root {
--font-family-sans: 'DM Sans', ui-sans-serif, system-ui, sans-serif;
}
Note: DM Sans 500 approximates Camera's 400 (Camera sits visually heavier). Adjust weight mappings accordingly if the substitute feels too light.
Known Gaps
- Hover state styling: Per the no-hover policy, all
:hoverpseudo-class styles are absent. The frontmatter documents Default and Active/Pressed states only; hover must be designed at implementation time following the transition tokens provided. - Loading/skeleton states: While
shimmer-gradientandshinekeyframes exist in the CSS, the exact skeleton component structure (border-radius, background color for skeleton items, animation duration) wasn't extractable from the static screenshot. - Form validation states: Beyond focus, error (
{colors.error}is defined but usage context is inferred), success, and disabled states for inputs aren't visually documented. - Dropdown/menu panels: The nav shows dropdown triggers (chevrons) but the actual popover/panel contents, their shadows, and their internal layout aren't visible.
- Mobile navigation collapse: The hamburger menu, slide-out drawer, or alternate mobile nav structure is inferred from responsive classes but not pictured.
- Below-fold content: Feature grids, testimonials, pricing tables, integrations showcase, and footer detail are entirely absent from this hero-focused screenshot. Their components, layouts, and potential sub-system dialects (e.g., "pricing card" with its own surface/color rules) are unknown.
- Dark mode: The entire extraction is from light mode (
{extensions.mode}: light). A potential dark mode — inverting surfaces to near-black and text to white, with adjusted gradient treatment — is not documented. - Exact gradient values: The hero gradient's precise color stops, angles, and blur radii are implemented in CSS not captured as structured data. Reimplementation requires visual approximation from the screenshot.
- Logo icon specifics: The multicolored party-popper logo mark's exact SVG path, gradient fills, and animation (if any) are custom assets not analyzable from CSS alone.
- Accessibility focus-visible styles: While focus shadows are documented for inputs, the exact
:focus-visiblering treatment (outline offset, color, radius) for keyboard navigation on buttons, links, and interactive elements is partial.