--- name: pulse-design-system description: Generation contract for the Pulse/Post visual system. Load this whenever an AI agent generates a new Pulse screen, component variant, or React extraction, so output stays inside the existing design system instead of inventing a new dashboard style. ---
Pulse / Post AI Generation Guide
The implementation source is the standalone component library under design-system/handoff/components/ - one folder per component with its own HTML + CSS, sharing components/tokens.css, browsable via components/html-component-preview.html. The React app (demo/pulse-react/) is paused and kept only as legacy reference. Tokens live in components/tokens.css (mirrored from demo/pulse-react/src/tokens.css); the component inventory and contracts are in design-system/component-library.md, and the visual handbook is design-system/handoff/design-system.html.
Treat that component library as the generation source, like Pulse's internal shadcn-style registry. New screens should compose the canonical component contracts, token families, variants, and states first; page-local markup is a fallback only when a pattern is genuinely feature-specific or still marked as a candidate component.
Prompt contract
Before creating new markup, identify which component category the work belongs to: Foundation, General, Layout, Navigation, Data entry, Data display, Feedback, or Business pattern. Reuse the existing primitive or pattern when it exists; when it does not, prefer filling the missing category with a small shared component over adding another page-local one-off. The highest-risk gaps are Data entry (Field, Input, Textarea, Select), Feedback (Popover, Tooltip, Modal, Drawer, Skeleton), and Data display (MetricBlock, DataRow, EmptyState, DescriptionList, TableLite). This is a taxonomy rule only: do not adopt another library's visual style.
Extraction order is: form fields first, overlays second, feedback states third, data display fourth, and business patterns last. Start from repeated local implementations in Signal, Calendar, Analytics, ActionItems, Campaign production, and Strategy. A shared component is ready only when it defines behavior, state, accessibility, placement, validation, or a reusable data anatomy; visual-only repetition can stay as local composition plus tokens.
Generate Post product screens using the existing Pulse/Post visual system:
Typography. Manrope is the platform typeface - 400/500/600/700, with font-variant-numeric: tabular-nums for aligned numerics. The heading system has a stronger product workspace entrance tier: page display 64 (--type-page-display / --type-page-title) when the title carries the screen without a kicker, standard H1 48 (--type-h1), H2 section / sub 28 (--type-h2), H3 21, H4 / card title 18, body 14, caption / description 13 (--type-caption), label 11, metric tabular. Section and sub headings stay substantial - do not divide hierarchy by shrinking everything to tiny type; lean on spacing, weight, and tonal labels. Build hierarchy from size, spacing, position, and structure - never from heavier weight; headings cap at medium, with semibold allowed only for optical support at display sizes, and a title is never made important by the heaviest Bold. The content headings use an 8px support gap (--heading-gap); 64px page display titles use a larger 20px support gap (--display-heading-gap) so the subtitle reads as its own calm row. One typeface for title, body, number, label, and metric - never switch fonts to emphasize a title. The single exception is --font-report (Newsreader serif), used only for stylized report display titles above 64px (--type-report-display), weight capped at medium (400-500) with italic available - never body, UI, labels, numbers, or standard H1-H4 headings. Geist Mono, Open Sans, Inter, Canela, and Satoshi are not in the system.
Surfaces. The primary palette is neutral: clean gray stage (#f4f7f7) with three very soft cyan radial blooms washed across the page; neutral canvas (#f8faf9) only when grouping is useful; glass outer bentos (rgba(255,255,255,0.28) + 36px backdrop blur) so the page wash bleeds through; solid white inner cards for reading; ink (#1d1d1f) for focus and active chrome. Keep page width restrained and avoid cold blue-gray casts in the shell, sidebar, and module backgrounds.
Radius. The hierarchy is 16px outer bento / 14px in-card slot / 12px inner card. Never repeat the same radius across nested layers; never use the deprecated 22-30px product radii. Pills stay fully rounded.
Cyan. Pulse cyan (#49e0f5) is the ready-state family and neutral diagram color. Do not use it as ambient background, generic progress, positive metrics, or decorative active chrome. Ready text uses cyan 700 (#0D7685) on a light cyan fill; diagram-neutral paths use primary cyan.
Status layer split. Keep status tags, data trends, and diagram semantics separate. Status tags use one compact outlined pill scale: green #43BA51 for positive, active/live, and approved; blue #3987F3 for suggested action and scheduled; amber #F19A08 for risk, negative, and on hold; ready uses a light cyan background with #0D7685 text; purple #6366F1 means in progress. Red is not a status tag color.
Data trend and diagram colors. Red #EF4444 is reserved for declining data only: negative delta, drop-off, loss, or a metric moving down. Use green #43BA51 for upward trends and blue #3987F3 for stable trends. Diagrams use primary cyan #49E0F5 for neutral paths, green for best performance, and amber for worst performance.
Exempt colors (platform brands and calendar today). Two color sets sit deliberately OUTSIDE the semantic ladder above. Platform brand glyphs (Instagram, Pinterest, YouTube, LinkedIn, Facebook, TikTok, X) are external marks, not Pulse status/data colors — consume them from the --platform-* tokens, one canonical value per platform, and never route them through the status/severity/trend ramps. The calendar "today" marker keeps a red accent by industry convention (mainstream calendars mark today in red); this is the one sanctioned use of red in chrome and does not weaken the "red = declining data only" rule everywhere else.
Generation and legacy wording. Generation state is process state, not data classification. Live/approved/published are green, ready is cyan-dark on a light cyan fill, scheduled is blue, on hold/risk is amber, in progress/rendering is purple, and queued is gray. Do not map "risk" or "protect now" to red unless the data itself is falling.
Generation status ladder. Use this ladder consistently: Queued neutral gray; Scheduled blue #3987F3; In progress, Generating, Rendering, and Building purple #6366F1; Ready light cyan with #0D7685 text; Approved, Live, Published, and Completed green #43BA51; On hold, Blocked, Failed, and Needs attention amber #F19A08. Red never appears in generation status. Status dots are flat solid markers only. Do not add glow, halo, ping, pulse, or soft outward rings around dots; selected or active states should be expressed with surface tone, border, text weight, or the standard focus ring.
Color depth. Every semantic color has the same six stops as cyan (50/100 soft fills, 200 line, 500 base, 600 text/dot on light, 700 deepest): --cyan-*, --success-*, --red-*, --amber-*, --blue-*, --indigo-*. Build hierarchy with these tones and the five text levels (--text-1 primary / --text-5 disabled) and the ink/neutral surface steps (--canvas / --surface / --surface-2/3) before adding a border. --green-* and --pulse-lime-* are legacy cyan aliases, not the new green; use --success-* when you mean completion.
Progress. Progress bars and production tracks use a single solid semantic fill, not gradients. Use cyan 600 for active pipeline/progress, success green for completed segments, blue for scheduled/logistics progress, indigo for rendering/generation, and neutral gray for pending/draft. Segmented progress may place multiple solid segments next to each other, but each segment remains flat. Do not use green-to-cyan, blue-to-cyan, or any decorative gradient to make progress feel more premium.
States. Use shared state layers for hover, focus, pressed, selected, and disabled; do not invent one-off hover colors. Shadow depth follows information hierarchy and elevation, not card size: overlays / floating layers (popover, modal, dropdown, dock, AI panel) get a strong shadow; an elevated primary surface gets a light-to-medium resting shadow; the base layer - stage, section / background containers, flat tonal blocks, data-highlight metric cards, buttons, and inline groups - carries no shadow and reads by tone, fill, spacing, and border, gaining lift only on hover, focus, or true elevation. Map to --shadow-* tokens, never one-off shadows. Dark CTAs sit flat on the card by default and gain only a light lift on hover. Keyboard focus always gets a visible ring.
Cards. Media previews show the image only; campaign info and due timing sit in the card body; current status belongs in the top-right status pill, with progress folded into that pill when needed. No second status or progress row beneath the description. Decision/action cards use one command title plus campaign info and current status - no duplicate helper chips.
Command summaries. Use CommandSummary when a page needs one operator decision before details: one sentence, a compact status row, MetricBlock-style metrics, a current/done/queued stage rail, and one primary action. Do not replace it with a row of equal-weight cards or multiple competing CTAs.
Campaigns. Always the React CampaignRow pattern: one row per campaign, visible PostChips, a +N more strip for scale, a right-state panel that changes with chip selection, and a closed-by-default five-step CampaignPipeline opened by selected chips or hidden tasks. Never one card per post. Hidden MoreTask cards reuse the exact PostChip anatomy: status pill, clamped title, numbered footer, and PlatformBadge icon. Queued, planned, rendering, and ready change only by generation-status color, not by card structure. PlatformBadge must use the approved logo PNG assets, not hand-drawn social glyphs or visible raw codes such as IG, TT, LI, FB, or X. Keep the readable platform name in aria-label, title, or expanded metadata. Official PNGs render inside the badge at the shared visual glyph size; use the per-platform visual-size variable when a brand asset ships with extra canvas or background padding. Do not use raw contain sizing that makes padded assets look smaller.
AI assistant. A floating inset card on the right that compresses the main view via body.ai-panel-open; inner two-column grids collapse to one column when the panel is open below ~1600px viewport. Conversations are selected from Sidebar recent chat; the AI panel header keeps only the close action. Do not add a menu/list CTA to the AI panel header.
Report callouts. ReportCallout rows use an icon tile, compact role pill, type weight, and quiet metadata for hierarchy. Do not use left rail stripes, stacked color bars, or trailing arrow affordances. Risk/watch uses amber, opportunity uses success green, and action uses suggested-action blue.
Sidebar. Keep the app rail taxonomy to Brand, Workspace, and Recent chat. Workspace includes the brand switcher plus all former Perception / Creative destinations; do not introduce Studio as a standalone nav destination. In collapsed rail states, page navigation is icon-only and each visible recent conversation keeps its own compact dot affordance.
Layout and reading rhythm. Keep section containers unframed; use cards only for repeated items, metrics, reports, media, actions, and campaign rows. Start shared page structure from the Grid component source (.pulse-grid, .pulse-grid--document, .pulse-grid--section, .pulse-grid--content, .pulse-grid--auto, .pulse-grid--split) before inventing a page-local grid. Do not make hierarchy by stacking borders or nesting cards. Use color, tone, background layers, type weight, spacing, and vertical grouping first. Avoid long rows of many parallel blocks unless side-by-side comparison is the point; prefer a calmer top-to-bottom reading path. Inside one large container, use light dividers or spacing for local grouping only, not another full framed surface. Carry emphasis with a tonal fill - a quiet light container with the key datum on a slightly stronger block - rather than a heavier outline; aim for a lighter, looser surface with breathing room. Preserve existing hover, segmented-control, live-update, reveal, sidebar collapse, and pipeline interactions.
What to keep stable
| Area | Rule |
|---|---|
| Font | Manrope only - the single platform typeface; tabular-nums for numerics; named type roles only. |
| Surfaces | Page wash carries the brand tint; outer bentos are glass, inner cards solid white, ink covers one or two anchors. No nested glass-on-glass, no painted-cyan bentos. |
| Radius | Step 16 / 14 / 12 outer to inner. Pills full. No repeated radius across nesting, no 22-30px scale. |
| Color | Primary surfaces are black, white, neutral gray. Primary cyan is ready/diagram-neutral; green positive/data-up/best; blue suggested/scheduled/stable; amber risk/on-hold/worst; purple in progress; red data-down only. |
| Status | Routine chips use compact semantic pills: green live/approved, blue scheduled/suggested, amber risk/on-hold, cyan ready, purple in progress, gray queued. |
| Contrast | Body text stays on ink or muted neutral. Cyan 700 (#0D7685) is reserved for ready text on light cyan. Primary cyan is for ready fills and neutral diagram paths, not generic icons or actions. |
| Progress | Bars and production tracks use flat semantic fills, never decorative gradients. Segments can differ by meaning, but each segment is solid. |
| States | Hover/selected/focus/pressed/disabled use shared state layers; focus ring always visible. |
| Charts | Mono-cyan + ink: series slots --chart-1..6 in fixed order (slot 1 brand cyan, slot 2 ink, indigo/teal only as the 5–6 escape hatch); single series wears slot 1 only; context/"Other" wears --chart-muted; magnitude and ordered stages wear the --chart-seq-* ramp as solid steps; at most one ink --chart-emphasis anchor per chart; red only for declining data. Fills stay in the bright band (never darker than --cyan-600); no gray series, no warm hues, never rank/value-colored bars. Every chart ships visible value labels, a value legend, or the DataTable twin. Form follows the data type: counts → columns, continuous measures → lines (straight segments between samples; cosmetic smoothing only on dense ≳30-point series with non-overshooting interpolation), part-to-whole → share forms, open comparisons → bare ranked bars; one mark per time slot at a uniform step; bars zero-based (lines may window with a fade-out wash only); hatched tracks only for true fractions of a whole; independent scales must be declared. A chart must read without hover: label the y scale (or a real-valued scale legend) and the x slots; draw averages/targets as labeled 1px dashed hairlines (the only dashed lines — gridlines stay solid). On large areas keep ramps pale-dominant (saturated cyan + ink only on top bins/peaks) and alternate chart cards with neutral surfaces so the cyan doesn't fatigue. Full contract: component-library.md §11 "Charts (shared)". |
| Component taxonomy | Fill missing categories deliberately: Data entry, Feedback, and Data display come before new business-only one-offs. |
| Campaigns | One row per campaign; chips switch state; more reveals hidden posts; pipeline closed by default. |
| Motion | Animate transform, opacity, and shadow only. Preserve existing component interactions. |
| Copy | Action card titles are commands. Supporting text is context, not a paragraph report. |
What to avoid (negative prompt)
- No stripes. No diagonal hatching or unexplained decorative background texture. The one sanctioned exception is the chart meter/share track: its hatched remainder is a pale step of the same data ramp that encodes remaining capacity (owner decision 2026-07-07) — chart tracks only, never gray, never a background texture.
- One-layer glass. Outer bento is glass; inner content is solid. Never stack glass on glass, never give an inner card backdrop-filter, never raise outer white opacity past ~0.45 to "fake" presence - raise blur instead.
- No painted-on cyan. Brand color lives in the page wash and reads through the glass. Don't fill a bento with
--pulse-cyan-softor add a cyan border to suggest brand - that signal goes flat the moment a second card does it. - No cyan on structural chrome. Section numbers, letter indices (A/B/C), eyebrow pills, "open X" links, kicker labels, and decorative left borders are structural: they render in ink / text-3 / a 0.045 neutral wash. Save cyan for ready-state and neutral diagram semantics. Positive/active/approved status and upward data trends are green; in-progress machine work is purple.
- No clutter. No platform badges, extra slate rows, lifecycle dots, or secondary CTAs unless workflow-critical.
- No one-off control sprawl. Do not create page-local inputs, selects, popovers, modals, drawers, empty states, or metric rows when the same category is likely to appear elsewhere. Define the shared contract first, then compose the page-specific content inside it.
- No border scaffolding. Do not use borders or nested cards as the default way to explain structure. If a module feels unclear, first adjust tone, background, type weight, spacing, or vertical grouping.
- No tense horizontal scanning. Do not split one row into too many equal-weight blocks. A user should not need to sweep left-to-right across a row of small modules to understand the page.
- No horizontal scroll fallback. Tabs, state boards, chip rails, task strips, and data rows should fit by wrapping, splitting into calmer sections, compacting, or progressively moving lower-priority items into
+N more. Do not hide primary reading content off-canvas. - Hidden tab axis only inside the component. SegmentedTabs stay on one row and hide their internal scroll axis; pages still cannot depend on horizontal scrolling to reveal primary content.
- No fake premium. No neon shadows, huge gradients, mystery blobs, generic purple AI styling, or card-on-card sections.
- No loose cyan bars. Cyan must explain ready-state or diagram-neutral meaning, never a decorative strip for vibe.
- No gradient progress. Progress bars, production tracks, and completion meters use solid semantic fills only. Do not blend success into cyan, blue into cyan, or indigo into green.
- No multiple action surfaces. Zero or one saturated action card per page. Two means the page lost its anchor.
- No heavy type. Avoid bold body copy; use size, spacing, and color for hierarchy.
- No new semantics. Do not introduce new color meanings without updating the token table in
tokens.css.
Fail the output if
Text clips, colors do not explain state, card shadows form square artifacts, nested cards appear, or a user cannot tell the next action.