Skip to content
Library · Components

Components

The canonical building blocks, live. Every snippet is copy-pasteable HTML — no JavaScript required except where noted. Styles come from src/styles/design-system.css.

Buttons

Base .btn with variants. Accent is reserved for the single primary action per view; danger only for destructive actions.

html
<button class="btn btn-primary">Primary</button>
<button class="btn">Secondary</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Delete</button>
<button class="btn btn-sm">Small</button>
<button class="btn btn-lg">Large</button>
<button class="btn-icon" aria-label="Settings">…</button>

Split-ops hero & terminal card

Public-only composition for ReachOut 2.0.2: status strip, hybrid display heading, flat console actions, and a machine-readable agent transcript.

● reachout consolemcp: connectedaudit: ● rec
Marketing automation · reimagined for AI

Your agent runs your marketing

One operating layer for analytics, campaigns, contacts, and insights.

agent session
you❯ launch spring-digest
↳ segments.resolve engaged_30d OK
Queued 24,188 recipients.
tools: 37● rec
html
<section class="hero-console texture-dots">
  <div class="console-status">…</div>
  <div class="hero-console-grid">
    <div class="hero-console-lead">…</div>
    <div class="hero-console-session">
      <div class="termcard">…</div>
    </div>
  </div>
</section>

Console buttons

Public CTAs only. The sigil is visual; the approved CTA wording and authenticated state remain unchanged.

html
<a class="cbtn cbtn-primary" href="/signup">Get Started</a>
<a class="cbtn cbtn-ghost" href="/demo">See the live demo</a>

Diff compare strip

A compact public comparison. Signs keep the meaning visible without relying on color.

reachout vs legacy automation
+MCP tool calls
+Every agent call logged
−Visual journey builders
html
<div class="diff">
  <div class="diff-head">reachout vs legacy automation</div>
  <div class="diff-row plus"><span class="sign">+</span><span class="diff-copy">MCP tool calls</span></div>
  <div class="diff-row minus"><span class="sign">−</span><span class="diff-copy">visual builders</span></div>
</div>

Pricing readout

Homepage pricing summary. The pricing page retains its fuller calculator and FAQ composition.

Starter$9.99 / seatWeb analytics · MCP · insights
Pro$20 / seat / month10k emails · 1k MCP calls · 1k insights
Max$100 / seat / month100k emails · 5k MCP calls · 5k insights
html
<div class="readout">
  <div class="readout-row"><span class="readout-tier">Starter</span>…</div>
  <div class="readout-row selected"><span class="readout-tier">Pro</span>…</div>
  <div class="readout-row"><span class="readout-tier">Max</span>…</div>
</div>

Capability card

Console-framed public feature card with a machine label, readable description, and quiet status footer.

Website analyticsstudio
First-party, identified, no aggregation
status: shipped
html
<article class="capcard">
  <div class="capcard-head"><span>Website analytics</span><span class="capcard-surface">studio</span></div>
  <div class="capcard-body">First-party, identified, no aggregation</div>
  <div class="capcard-foot">status: <span class="capcard-status">shipped</span></div>
</article>

Dotted texture

Use .texture-dots only on the public hero and section dividers. It adapts automatically to both themes.

html
<div class="texture-dots ds-texture-preview"></div>

Badges

Status at a glance — mono, uppercase, optional pulsing dot. Use .badge-live for running things, .badge-done for success, .badge-err for failures, .badge-warn for limits, .badge-draft for inactive.

LiveSentFailedNear capDraftv1.0.1
html
<span class="badge badge-live"><span class="dot"></span>Live</span>
<span class="badge badge-done"><span class="dot"></span>Sent</span>
<span class="badge badge-err"><span class="dot"></span>Failed</span>
<span class="badge badge-warn"><span class="dot"></span>Near cap</span>
<span class="badge badge-draft">Draft</span>
<span class="badge">v1.0.1</span>

Card

The base surface: 1px border, --bg-elev, --radius-lg, never a shadow. Compose with .card-head, .card-body, .card-foot.

Deliverability

Last 30 days across all campaigns

Delivered
98.2%
Bounced
1.1%
Complaints
0.02%
Updated 4 min agosrc: ses-eu-1
html
<div class="card">
  <div class="card-head">
    <div class="card-head-main">
      <h3 class="card-title">Deliverability</h3>
      <p class="card-sub">Last 30 days across all campaigns</p>
    </div>
    <div class="card-head-actions"><button class="btn btn-sm">Export</button></div>
  </div>
  <div class="card-body">…</div>
  <div class="card-foot"><span>Updated 4 min ago</span><span class="mono">src: ses-eu-1</span></div>
</div>

Stat cards

The canonical metric tile: sans label, mono tabular value, semantic delta. Wrap in .stat-grid (4-up, responsive). Mark selectable cards with button.stat-card + .selected.

Emails sent ↗ +18.2%12,408vs 10,498 previous period
Open rate ↗ +2.4 pts41.7%Unique opens / delivered
Bounce rate ↗ +0.3 pts1.1%Hard bounces / sent
MCP calls → 0.0%862Agent tool invocations
html
<div class="stat-grid">
  <div class="stat-card">
    <span class="stat-label">Emails sent <span class="delta up">↗ +18.2%</span></span>
    <span class="stat-value">12,408</span>
    <span class="stat-sub">vs 10,498 previous period</span>
  </div>
  …
</div>

Delta

Signed change indicator. Semantic color, mono, arrow glyph. .delta-framed adds the bordered chip used in selectable stat cards.

↗ +18.2%↗ +0.3 pts→ 0.0%↗ +18.2%↗ +0.3 pts
html
<span class="delta positive">↗ +18.2%</span>
<span class="delta negative">↗ +0.3 pts</span>
<span class="delta neutral">→ 0.0%</span>
<span class="delta positive delta-framed">↗ +18.2%</span>

Forms

.field composes label + control + hint/error. Checkboxes, radios and switches are native inputs, themed.

Shown to your agent in tool calls.
Enter a valid sender address.
html
<div class="field">
  <label class="field-label" for="name">Campaign name <span class="req">*</span></label>
  <input id="name" type="text" placeholder="spring-launch" />
  <span class="field-hint">Shown to your agent in tool calls.</span>
</div>
<div class="field has-error">
  <label class="field-label" for="from">Sender</label>
  <input id="from" type="email" value="not-an-email" />
  <span class="field-error">Enter a valid sender address.</span>
</div>
<label class="check"><input type="checkbox" checked /> GDPR consent stored</label>
<label class="check radio"><input type="radio" name="r" checked /> Immediate send</label>
<label class="switch"><input type="checkbox" checked /> Live tracking</label>

Segmented control & tabs

Segmented for switching a view within a panel (aria-pressed); tabs for page-level navigation.

html
<div class="segmented" role="group" aria-label="Range">
  <button aria-pressed="false">7d</button>
  <button aria-pressed="true">30d</button>
  <button aria-pressed="false">3m</button>
</div>

<nav class="tabs" aria-label="Analytics sections">
  <a href="#" class="active" aria-current="page">Overview</a>
  <a href="#">Deliverability</a>
  <a href="#">Engagement</a>
</nav>

Alerts

Inline feedback. Info = accent, success = positive, warning = warning, danger = negative.

ⓘAgent access enabledYour MCP endpoint is reachable at mcp.usereachout.com.
✓Campaign sent12,408 emails delivered in 4m 12s.
⚠Approaching plan limit8,412 / 10,000 emails used this cycle.
✕Domain not verifiedDKIM record missing — sends are paused.
html
<div class="alert alert-info">…</div>
<div class="alert alert-success">…</div>
<div class="alert alert-warning">…</div>
<div class="alert alert-danger">…</div>

Modal

The one canonical dialog: .modal-backdrop > .modal > head/body/foot. createModalController() owns focus, isolation, Escape/backdrop close and restoration.

html
<div class="modal-backdrop">
  <div class="modal" role="dialog" aria-modal="true" aria-labelledby="m-title" tabindex="-1">
    <div class="modal-head">
      <div>
        <div class="modal-kicker">contacts.delete</div>
        <h3 id="m-title">Delete 2 contacts?</h3>
      </div>
      <button class="modal-close" aria-label="Close">✕</button>
    </div>
    <div class="modal-body">…</div>
    <div class="modal-foot">
      <span class="modal-foot-note">This cannot be undone.</span>
      <button class="btn">Cancel</button>
      <button class="btn btn-danger">Delete</button>
    </div>
  </div>
</div>

Progress

Thin meters for usage and send progress. Default accent; semantic states for ok/warn/err.

Emails this cycle8,412 / 10,000
html
<div class="progress"><span class="progress-fill" style="width: 64%"></span></div>
<div class="progress progress-ok">…</div>
<div class="progress progress-warn">…</div>
<div class="progress progress-err">…</div>

<div class="progress-labeled">
  <div class="progress-head"><span>Emails this cycle</span><b>8,412 / 10,000</b></div>
  <div class="progress progress-warn"><span class="progress-fill" style="width: 84%"></span></div>
</div>

Loading progress & skeleton

The viewport bar confirms route progress; skeletons preserve the shape and hierarchy of unresolved data. Motion respects reduced-motion preferences.

html
<div class="studio-page-progress" aria-hidden="true">
  <span class="studio-page-progress-fill"></span>
</div>
<div aria-hidden="true">
  <div class="skeleton skeleton-heading"></div>
  <div class="skeleton skeleton-line skeleton-line-wide"></div>
  <div class="skeleton skeleton-chart"></div>
</div>

Empty state

Every list and table needs one. Icon in a dashed frame, sans title, body copy, one primary action, optional mono hint for the agent path.

⌁

No segments yet

Segments target campaigns. Create one here, or ask your agent to build it from a natural-language rule.

mcp · segments.create
html
<div class="empty-state">
  <div class="empty-state-icon">⌁</div>
  <h3>No segments yet</h3>
  <p>Segments target campaigns. Create one here, or ask your agent.</p>
  <button class="btn btn-primary">Create segment</button>
  <div class="mono-note">mcp · segments.create</div>
</div>

Key-value list

Dense metadata display — sans keys, mono tabular values, dashed separators.

API key
ro_live_9f2…c41
Created
2026-07-14 09:32
Calls this cycle
862 / 1,000
Last used
4 min ago
html
<dl class="kv">
  <div class="kv-row"><dt>API key</dt><dd>ro_live_9f2…c41</dd></div>
  <div class="kv-row"><dt>Created</dt><dd>2026-07-14 09:32</dd></div>
  <div class="kv-row"><dt>Calls this cycle</dt><dd>862 / 1,000</dd></div>
</dl>

Code & terminal

.code-block with token colors (.tk-*). Machine content stays mono — this is the agent's native tongue.

bash
$ reachout campaigns send --id spring-launch
✓ validated segment 3,102 contacts
✓ queued 12,408 emails # est. 4m 12s
html
<div class="code-block">
  <span class="code-lang">bash</span>
  <pre><code><span class="tk-prompt">$</span> <span class="tk-cmd">reachout campaigns send</span> <span class="tk-flag">--id</span> spring-launch
<span class="tk-ok">✓</span> queued 12,408 emails <span class="tk-comment"># 4m 12s</span></code></pre>
</div>

Mockup frames

Product presentation for public pages: .mockup (browser chrome) and .mockup-terminal. Fill the body with a screenshot, a live iframe, or — preferred — real components at reduced scale.

● studio.usereachout.com/analytics
Sent12,408
Opens41.7%
Clicks6.2%
agent — mcp session
→ segments.estimate { "rule": "opened_last_30d" }
← { "contacts": 3102, "confidence": 0.94 }
html
<div class="mockup">
  <div class="mockup-chrome">
    <span class="mockup-dots"><i></i><i></i><i></i></span>
    <span class="mockup-url"><span class="lock">●</span> studio.usereachout.com/analytics</span>
  </div>
  <div class="mockup-body">…screenshot, iframe or CSS miniature…</div>
</div>