Chapter 07 / 12 · Data display

Data display

How MagicBlocks shows records. Tables for multi-column analysis, lists for single-record rows, chips and badges for status, avatars for people, progress for numbers, timelines for history, code blocks for snippets, and empty states for the in-between.

7.1 Data table

The primary surface for listing records. Mono uppercase headers (sortable), avatar+name+sub cell for people, right-aligned tabular numbers, and a row-actions button that appears on hover.

Standard table

.tbl

Sort indicator in pink on the active column. Warm row hover. Row divider uses hair-soft.

Contact Stage Last touch Value
AC
Alicia Chen
alicia@northpeak.co
Qualified 2h ago $48,000
MR
Marcus Reyes
marcus@trailhaus.io
Negotiation Yesterday $120,000
JP
Jordan Park
jordan@lumenfin.com
Won 3d ago $64,500
SK
Sam Kowalski
sam@ridgepine.co
Contacted 1w ago $12,750
<div class="tbl-wrap">
<table class="tbl">
  <thead>
    <tr>
      <th class="tbl-sort is-active">Contact <span class="tbl-sort-ic"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 15 6-6 6 6"/></svg></span></th>
      <th class="tbl-sort">Stage <span class="tbl-sort-ic"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg></span></th>
      <th class="tbl-sort">Last touch <span class="tbl-sort-ic"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg></span></th>
      <th class="tbl-right tbl-sort">Value <span class="tbl-sort-ic"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg></span></th>
      <th aria-label="Actions"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <div class="tbl-person">
          <span class="av" style="background:var(--info-soft); color: var(--info-text);">AC</span>
          <div><div class="tbl-name">Alicia Chen</div><div class="tbl-sub">alicia@northpeak.co</div></div>
        </div>
      </td>
      <td><span class="chip chip-blue">Qualified</span></td>
      <td><span class="mono tbl-mono">2h ago</span></td>
      <td class="tbl-right tbl-num">$48,000</td>
      <td class="tbl-right"><button class="tbl-icon" aria-label="Row actions"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
    </tr>
    <tr>
      <td>
        <div class="tbl-person">
          <span class="av" style="background:#FFE2EC; color:var(--accent-text);">MR</span>
          <div><div class="tbl-name">Marcus Reyes</div><div class="tbl-sub">marcus@trailhaus.io</div></div>
        </div>
      </td>
      <td><span class="chip chip-pink">Negotiation</span></td>
      <td><span class="mono tbl-mono">Yesterday</span></td>
      <td class="tbl-right tbl-num">$120,000</td>
      <td class="tbl-right"><button class="tbl-icon" aria-label="Row actions"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
    </tr>
    <tr>
      <td>
        <div class="tbl-person">
          <span class="av" style="background:#DDEFDD; color:#1E6B44;">JP</span>
          <div><div class="tbl-name">Jordan Park</div><div class="tbl-sub">jordan@lumenfin.com</div></div>
        </div>
      </td>
      <td><span class="chip chip-green">Won</span></td>
      <td><span class="mono tbl-mono">3d ago</span></td>
      <td class="tbl-right tbl-num">$64,500</td>
      <td class="tbl-right"><button class="tbl-icon" aria-label="Row actions"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
    </tr>
    <tr>
      <td>
        <div class="tbl-person">
          <span class="av" style="background:#F2E6FF; color:#5C2CA8;">SK</span>
          <div><div class="tbl-name">Sam Kowalski</div><div class="tbl-sub">sam@ridgepine.co</div></div>
        </div>
      </td>
      <td><span class="chip">Contacted</span></td>
      <td><span class="mono tbl-mono">1w ago</span></td>
      <td class="tbl-right tbl-num">$12,750</td>
      <td class="tbl-right"><button class="tbl-icon" aria-label="Row actions"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg></button></td>
    </tr>
  </tbody>
</table>
</div>
.tbl-wrap {
  background: var(--bg-paper); border: 1px solid var(--hair);
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--sh-1);
}
.tbl { width: 100%; border-collapse: collapse; font: 14px/1.4 var(--f-body); }
.tbl thead th {
  text-align: left; padding: 12px var(--s-4);
  font: 500 11px/1 var(--f-mono);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--fg-dim); background: var(--bg-sunken);
  border-bottom: 1px solid var(--hair);
  white-space: nowrap;
}
.tbl thead th.tbl-sort { cursor: pointer; user-select: none; }
.tbl thead th.tbl-sort:hover { color: var(--fg-soft); }
.tbl thead th.tbl-sort.is-active { color: var(--fg); }
.tbl-sort-ic { display: inline-flex; vertical-align: -2px; margin-left: 4px; color: var(--fg-faint); }
.tbl-sort.is-active .tbl-sort-ic { color: var(--accent-text); }
.tbl tbody tr { border-bottom: 1px solid var(--hair-soft); transition: background var(--dur-1) var(--ease); }
.tbl tbody tr:last-child { border-bottom: 0; }
.tbl tbody tr:hover { background: var(--bg-warm); }
.tbl td { padding: 14px var(--s-4); color: var(--fg); vertical-align: middle; }
.tbl-right { text-align: right; }
.tbl-num { font-variant-numeric: tabular-nums; font-weight: 600; }
.tbl-mono { font-size: 12.5px; color: var(--fg-soft); }
.tbl-person { display: flex; align-items: center; gap: var(--s-3); }
.tbl-name { font-weight: 600; color: var(--fg); }
.tbl-sub { font-size: 12px; color: var(--fg-dim); margin-top: 1px; }
.tbl-icon {
  background: transparent; border: 1px solid transparent; color: var(--fg-dim);
  width: 28px; height: 28px; border-radius: var(--r-sm);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.tbl-icon:hover { background: var(--bg-sunken); color: var(--fg); border-color: var(--hair); }
.av {
  width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 12px/1 var(--f-display); letter-spacing: 0.02em;
  flex-shrink: 0;
}

7.2 Table variants

Zebra striping with warm-3 on odd rows for longer analytic tables. Compact layout for dense activity logs where information density matters more than breathing room.

Striped rows

.tbl-striped

Odd rows get a whisper of warm-3. Use for analytic data with 5+ columns.

ChannelSentOpenedReply rate
Email1,20481212.4%
SMS34029828.1%
Voice927441.3%
DM17613018.8%
<div class="tbl-wrap">
<table class="tbl tbl-striped">
  <thead>
    <tr>
      <th>Channel</th><th>Sent</th><th>Opened</th><th class="tbl-right">Reply rate</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Email</td><td class="tbl-num">1,204</td><td class="tbl-num">812</td><td class="tbl-right tbl-num">12.4%</td></tr>
    <tr><td>SMS</td><td class="tbl-num">340</td><td class="tbl-num">298</td><td class="tbl-right tbl-num">28.1%</td></tr>
    <tr><td>Voice</td><td class="tbl-num">92</td><td class="tbl-num">74</td><td class="tbl-right tbl-num">41.3%</td></tr>
    <tr><td>DM</td><td class="tbl-num">176</td><td class="tbl-num">130</td><td class="tbl-right tbl-num">18.8%</td></tr>
  </tbody>
</table>
</div>
.tbl-striped tbody tr:nth-child(odd) { background: color-mix(in oklab, var(--warm-3) 40%, transparent); }
.tbl-striped tbody tr:hover { background: var(--bg-warm); }

Compact rows

.tbl-compact

Tighter padding, smaller type. Use for activity logs, changelogs, audit trails.

EventWhenBy
Lead qualified2mAgent
Email opened14mAlicia C.
Reply sent48mAgent
Meeting booked1hAlicia C.
Notes added2hMarcus R.
<div class="tbl-wrap">
<table class="tbl tbl-compact">
  <thead>
    <tr>
      <th>Event</th><th>When</th><th class="tbl-right">By</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Lead qualified</td><td class="mono tbl-mono">2m</td><td class="tbl-right">Agent</td></tr>
    <tr><td>Email opened</td><td class="mono tbl-mono">14m</td><td class="tbl-right">Alicia C.</td></tr>
    <tr><td>Reply sent</td><td class="mono tbl-mono">48m</td><td class="tbl-right">Agent</td></tr>
    <tr><td>Meeting booked</td><td class="mono tbl-mono">1h</td><td class="tbl-right">Alicia C.</td></tr>
    <tr><td>Notes added</td><td class="mono tbl-mono">2h</td><td class="tbl-right">Marcus R.</td></tr>
  </tbody>
</table>
</div>
.tbl-compact thead th { padding: 8px var(--s-3); }
.tbl-compact td { padding: 8px var(--s-3); font-size: 13px; }

7.3 Chips & tags

Small, pill-shaped labels for categories, statuses, and filters. Soft-tint backgrounds with matching hairline borders. Default is neutral sunken; colour variants map to semantic meaning.

Chip variants

.chip

Seven tones. Keep to one chip per piece of metadata so colour retains meaning.

Default Primary Qualified Won At risk Lost Nurture
<div class="chip-row">
  <span class="chip">Default</span>
  <span class="chip chip-pink">Primary</span>
  <span class="chip chip-blue">Qualified</span>
  <span class="chip chip-green">Won</span>
  <span class="chip chip-amber">At risk</span>
  <span class="chip chip-red">Lost</span>
  <span class="chip chip-purple">Nurture</span>
</div>
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  font: 500 12px/1.2 var(--f-body);
  background: var(--bg-sunken); color: var(--fg-soft);
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.chip-pink   { background: var(--accent-soft); color: var(--accent-text); border-color: color-mix(in oklab, var(--accent) 25%, transparent); }
.chip-blue   { background: var(--info-soft); color: var(--info-text); border-color: color-mix(in oklab, var(--info) 25%, transparent); }
.chip-green  { background: #E3F2E3; color: #1E6B44; border-color: color-mix(in oklab, #1E6B44 15%, transparent); }
.chip-amber  { background: #FFF0D6; color: #8A5A00; border-color: color-mix(in oklab, #8A5A00 15%, transparent); }
.chip-red    { background: var(--error-soft); color: var(--error-text); border-color: color-mix(in oklab, var(--error) 25%, transparent); }
.chip-purple { background: #EFE4FF; color: #5C2CA8; border-color: color-mix(in oklab, #5C2CA8 15%, transparent); }
.chip-row { display: flex; flex-wrap: wrap; gap: var(--s-2); }

Dismissible chip

.chip-dismiss

Used for removable filters and selected tags. The × sits outside the text baseline so it doesn't disrupt the word.

SaaS Fintech Inbound
<div class="chip-row">
  <span class="chip chip-dismiss">SaaS <button aria-label="Remove">×</button></span>
  <span class="chip chip-dismiss">Fintech <button aria-label="Remove">×</button></span>
  <span class="chip chip-dismiss chip-pink">Inbound <button aria-label="Remove">×</button></span>
</div>
.chip-dismiss button {
  background: transparent; border: 0; padding: 0;
  width: 16px; height: 16px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 14px/1 var(--f-display); color: inherit; opacity: 0.6;
  cursor: pointer; margin-left: 2px; margin-right: -4px;
  transition: opacity var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.chip-dismiss button:hover { opacity: 1; background: color-mix(in oklab, currentColor 15%, transparent); }

7.4 Badges & status dots

Smaller than chips and purpose-built for status. A status dot with a glow halo reads instantly at small sizes. Count badges are ink on paper (or pink for notification counts).

Status + count + label badges

.badge

Status dots include a faint halo so they remain legible on warm backgrounds. Count badges use tabular mono for alignment.

Live Degraded Down Syncing Paused
12 3 New Beta
<div class="badge-row">
  <span class="badge"><span class="dot dot-green"></span> Live</span>
  <span class="badge"><span class="dot dot-amber"></span> Degraded</span>
  <span class="badge"><span class="dot dot-red"></span> Down</span>
  <span class="badge"><span class="dot dot-blue"></span> Syncing</span>
  <span class="badge"><span class="dot dot-grey"></span> Paused</span>
</div>
<div class="badge-row" style="margin-top: var(--s-4);">
  <span class="badge badge-count">12</span>
  <span class="badge badge-count badge-pink">3</span>
  <span class="badge badge-count badge-dot"><span class="dot dot-pink"></span></span>
  <span class="badge badge-new">New</span>
  <span class="badge badge-beta">Beta</span>
</div>
.badge {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 10px;
  min-height: 22px;                  /* unify height across every badge variant */
  box-sizing: border-box;
  font: 500 12px/1 var(--f-body); color: var(--fg);
  background: var(--bg-paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
}
.badge-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; position: relative; }
.dot-green  { background: var(--success); box-shadow: 0 0 0 3px color-mix(in oklab, var(--success) 22%, transparent); }
.dot-amber  { background: var(--warning); box-shadow: 0 0 0 3px color-mix(in oklab, var(--warning) 22%, transparent); }
.dot-red    { background: var(--error);   box-shadow: 0 0 0 3px color-mix(in oklab, var(--error)   22%, transparent); }
.dot-blue   { background: var(--info);    box-shadow: 0 0 0 3px color-mix(in oklab, var(--info)    22%, transparent); }
.dot-grey   { background: var(--fg-faint); }
.dot-pink   { background: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.badge-count {
  min-width: 22px; height: 22px; padding: 0 7px;
  border-radius: 999px;
  background: var(--fg); color: var(--bg);    /* pair --fg with --bg so BOTH flip in dark mode (warm-on-ink, ink-on-white) */
  font: 600 11px/1 var(--f-mono); letter-spacing: 0.02em;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0;
}
.badge-pink { background: var(--accent); }
/* Dot-only count badge — keep the 22×22 footprint so the row stays aligned;
   the inner .dot carries its own visible pulse/halo. */
.badge-dot {
  background: transparent; border: 0; padding: 0;
  min-width: 22px; width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
}
.badge-new {
  background: var(--accent); color: var(--paper); border: 0;
  font-family: var(--f-mono); font-size: 10.5px; text-transform: uppercase;
  letter-spacing: 0.1em; padding: 4px 10px;
}
.badge-beta {
  background: transparent; color: var(--accent-text);
  border: 1px solid var(--accent);
  font-family: var(--f-mono); font-size: 10.5px; text-transform: uppercase;
  letter-spacing: 0.1em; padding: 3px 10px;
}

7.5 Avatars

Circle with initials and a soft tinted background. Five sizes (xs–xl) cover density from inline metadata chips to large profile heroes. Stacks overlap by 8px with a paper ring between layers.

Sizes, ring, stack

.av · .av-stack

Tint background + darker text at ~2.5x ratio keeps contrast accessible. Use .av-ring for 'current user' or 'selected'. Use +N overflow for groups >4.

AC MR JP SK MB JS
AC MR JP SK +7
<div class="av-row">
  <span class="av av-xs" style="background:var(--info-soft); color: var(--info-text);">AC</span>
  <span class="av av-sm" style="background:#FFE2EC; color:var(--accent-text);">MR</span>
  <span class="av" style="background:#DDEFDD; color:#1E6B44;">JP</span>
  <span class="av av-lg" style="background:#F2E6FF; color:#5C2CA8;">SK</span>
  <span class="av av-xl" style="background:var(--ink); color:var(--paper);">MB</span>
  <span class="av av-lg av-ring" style="background:var(--accent-soft); color: var(--accent-text);">JS</span>
</div>
<div style="margin-top: var(--s-5);">
  <div class="av-stack">
    <span class="av av-sm" style="background:var(--info-soft); color: var(--info-text);">AC</span>
    <span class="av av-sm" style="background:#FFE2EC; color:var(--accent-text);">MR</span>
    <span class="av av-sm" style="background:#DDEFDD; color:#1E6B44;">JP</span>
    <span class="av av-sm" style="background:#F2E6FF; color:#5C2CA8;">SK</span>
    <span class="av av-sm av-more">+7</span>
  </div>
</div>
.av-row { display: flex; align-items: center; gap: var(--s-3); }
.av-xs { width: 20px; height: 20px; font-size: 9px; }
.av-sm { width: 26px; height: 26px; font-size: 10.5px; }
.av-lg { width: 40px; height: 40px; font-size: 14px; }
.av-xl { width: 56px; height: 56px; font-size: 19px; }
.av-ring { box-shadow: 0 0 0 2px var(--bg-paper), 0 0 0 4px var(--accent); }
.av-stack { display: inline-flex; }
.av-stack .av { margin-left: -8px; box-shadow: 0 0 0 2px var(--bg-paper); }
.av-stack .av:first-child { margin-left: 0; }
.av-more {
  background: var(--bg-sunken) !important; color: var(--fg-soft) !important;
  font-family: var(--f-mono); font-weight: 600;
}

7.6 Data lists & key-value

When a table is too heavy, use a list-row surface: avatar + primary + sub + status chip per row. For record details, use the key-value grid — mono uppercase keys, plain-text values.

List rows

.list-rows

Same surface language as the table but optimized for single-record-per-row scanning.

  • AC
    Alicia Chen
    Replied 2h ago · via SMS
    Qualified
  • MR
    Marcus Reyes
    Meeting booked · yesterday
    Booked
  • JP
    Jordan Park
    Followed up · 3 days ago
    Nurture
<ul class="list-rows">
  <li>
    <span class="av" style="background:var(--info-soft); color: var(--info-text);">AC</span>
    <div class="lr-main">
      <div class="lr-name">Alicia Chen</div>
      <div class="lr-sub">Replied 2h ago · via SMS</div>
    </div>
    <span class="chip chip-green">Qualified</span>
  </li>
  <li>
    <span class="av" style="background:#FFE2EC; color:var(--accent-text);">MR</span>
    <div class="lr-main">
      <div class="lr-name">Marcus Reyes</div>
      <div class="lr-sub">Meeting booked · yesterday</div>
    </div>
    <span class="chip chip-blue">Booked</span>
  </li>
  <li>
    <span class="av" style="background:#DDEFDD; color:#1E6B44;">JP</span>
    <div class="lr-main">
      <div class="lr-name">Jordan Park</div>
      <div class="lr-sub">Followed up · 3 days ago</div>
    </div>
    <span class="chip">Nurture</span>
  </li>
</ul>
.list-rows {
  list-style: none; padding: 0; margin: 0;
  background: var(--bg-paper); border: 1px solid var(--hair);
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--sh-1);
}
.list-rows li {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 14px var(--s-4);
  border-bottom: 1px solid var(--hair-soft);
  transition: background var(--dur-1) var(--ease);
}
.list-rows li:last-child { border-bottom: 0; }
.list-rows li:hover { background: var(--bg-warm); }
.lr-main { flex: 1; min-width: 0; }
.lr-name { font-weight: 600; color: var(--fg); font-size: 14px; }
.lr-sub { font-size: 12.5px; color: var(--fg-dim); margin-top: 2px; }

Key-value grid

.kv

Two-column grid with hairline dividers. Keys render in mono uppercase so the eye can scan labels and values independently.

Account
Northpeak Mortgage
Owner
Alicia Chen
Created
2026-04-18
Pipeline value
$48,000
Stage
Qualified
Last activity
Replied by SMS · 2h ago
<dl class="kv">
  <div><dt>Account</dt><dd>Northpeak Mortgage</dd></div>
  <div><dt>Owner</dt><dd>Alicia Chen</dd></div>
  <div><dt>Created</dt><dd><span class="mono">2026-04-18</span></dd></div>
  <div><dt>Pipeline value</dt><dd class="tbl-num">$48,000</dd></div>
  <div><dt>Stage</dt><dd><span class="chip chip-blue">Qualified</span></dd></div>
  <div><dt>Last activity</dt><dd>Replied by SMS <span class="fg-dim">· 2h ago</span></dd></div>
</dl>
.kv {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--hair-soft); border: 1px solid var(--hair);
  border-radius: var(--r-lg); overflow: hidden;
  margin: 0;
}
.kv > div {
  display: grid; grid-template-columns: 140px 1fr; gap: var(--s-3);
  padding: 12px var(--s-4);
  background: var(--bg-paper);
  align-items: baseline;
}
.kv dt {
  font: 500 11px/1 var(--f-mono);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--fg-dim);
}
.kv dd { margin: 0; color: var(--fg); font-size: 14px; }
.fg-dim { color: var(--fg-dim); }
@media (max-width: 640px) { .kv { grid-template-columns: 1fr; } }

7.7 Progress

Linear bars for single-dimension progress (task completion, quota, loading). Rings for at-a-glance percentages in dashboards, where the space is small and the number is the hero.

Linear bar

.prog

6px track, pink fill by default. Semantic variants green (positive) and amber (attention). Label sits above, tabular-number value aligned right.

Pipeline coverage72%
Reply rate41%
Quota at risk18%
<div class="prog-demo">
  <div class="prog">
    <div class="prog-head"><span class="prog-label">Pipeline coverage</span><span class="prog-val mono">72%</span></div>
    <div class="prog-track"><div class="prog-fill" style="width: 72%;"></div></div>
  </div>
  <div class="prog">
    <div class="prog-head"><span class="prog-label">Reply rate</span><span class="prog-val mono">41%</span></div>
    <div class="prog-track"><div class="prog-fill prog-green" style="width: 41%;"></div></div>
  </div>
  <div class="prog">
    <div class="prog-head"><span class="prog-label">Quota at risk</span><span class="prog-val mono">18%</span></div>
    <div class="prog-track"><div class="prog-fill prog-amber" style="width: 18%;"></div></div>
  </div>
</div>
.prog-demo { display: flex; flex-direction: column; gap: var(--s-4); width: 100%; max-width: 480px; }
.prog-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.prog-label { font: 500 13px/1 var(--f-body); color: var(--fg-soft); }
.prog-val { font-size: 13px; color: var(--fg); font-variant-numeric: tabular-nums; }
.prog-track {
  height: 6px; background: var(--bg-sunken);
  border-radius: var(--r-pill); overflow: hidden;
  position: relative;
}
.prog-fill {
  height: 100%; background: var(--accent);
  border-radius: inherit;
  transition: width var(--dur-4) var(--ease);
}
.prog-green  { background: var(--success); }
.prog-amber  { background: var(--warning); }

Progress ring

.ring

SVG stroke technique — dashoffset controls the filled arc. Dasharray = 2πr. Paired with a tabular number and mono label for dashboard blocks.

72%
Coverage
41%
Reply rate
18%
At risk
<div class="rings">
  <div class="ring-item">
    <svg class="ring" width="72" height="72" viewBox="0 0 72 72">
      <circle class="ring-bg" cx="36" cy="36" r="30" fill="none" stroke-width="6"/>
      <circle class="ring-fg" cx="36" cy="36" r="30" fill="none" stroke-width="6"
              stroke-dasharray="188.5" stroke-dashoffset="52.8" transform="rotate(-90 36 36)"/>
    </svg>
    <div>
      <div class="ring-val">72<span class="ring-unit">%</span></div>
      <div class="ring-label">Coverage</div>
    </div>
  </div>
  <div class="ring-item">
    <svg class="ring" width="72" height="72" viewBox="0 0 72 72">
      <circle class="ring-bg" cx="36" cy="36" r="30" fill="none" stroke-width="6"/>
      <circle class="ring-fg ring-green" cx="36" cy="36" r="30" fill="none" stroke-width="6"
              stroke-dasharray="188.5" stroke-dashoffset="111.2" transform="rotate(-90 36 36)"/>
    </svg>
    <div>
      <div class="ring-val">41<span class="ring-unit">%</span></div>
      <div class="ring-label">Reply rate</div>
    </div>
  </div>
  <div class="ring-item">
    <svg class="ring" width="72" height="72" viewBox="0 0 72 72">
      <circle class="ring-bg" cx="36" cy="36" r="30" fill="none" stroke-width="6"/>
      <circle class="ring-fg ring-amber" cx="36" cy="36" r="30" fill="none" stroke-width="6"
              stroke-dasharray="188.5" stroke-dashoffset="154.6" transform="rotate(-90 36 36)"/>
    </svg>
    <div>
      <div class="ring-val">18<span class="ring-unit">%</span></div>
      <div class="ring-label">At risk</div>
    </div>
  </div>
</div>
.rings { display: flex; gap: var(--s-6); flex-wrap: wrap; }
.ring-item { display: flex; align-items: center; gap: var(--s-3); }
.ring-bg { stroke: var(--bg-sunken); }
.ring-fg { stroke: var(--accent); stroke-linecap: round; transition: stroke-dashoffset var(--dur-4) var(--ease); }
.ring-green { stroke: var(--success); }
.ring-amber { stroke: var(--warning); }
.ring-val { font: 600 22px/1 var(--f-display); color: var(--fg); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.ring-unit { font-size: 13px; color: var(--fg-dim); margin-left: 2px; }
.ring-label { font: 500 11px/1 var(--f-mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--fg-dim); margin-top: 4px; }

7.8 Timeline / activity feed

Vertical activity log. Each item is a dot on a hairline rail, with a timestamp on the right. State is encoded in the dot: filled ink = done, pink with halo = now, ring = scheduled.

Activity timeline

.timeline

Use for contact histories, deal events, agent action logs. Pair with the compact table for full audit context.

  1. Lead qualified2h ago

    Agent confirmed intent, budget, and timeline. Routed to Alicia.

  2. Follow-up sent1h ago

    Personalised summary + calendar link sent by SMS.

  3. Awaiting replynow

    Agent is monitoring the thread for a response.

  4. Re-engage in 48hscheduled

    If no reply, agent sends a soft nudge with a different angle.

<ol class="timeline">
  <li class="tl-item tl-done">
    <div class="tl-marker"><span class="tl-dot"></span></div>
    <div class="tl-body">
      <div class="tl-head"><strong>Lead qualified</strong><span class="tl-time mono">2h ago</span></div>
      <p class="tl-desc">Agent confirmed intent, budget, and timeline. Routed to Alicia.</p>
    </div>
  </li>
  <li class="tl-item tl-done">
    <div class="tl-marker"><span class="tl-dot"></span></div>
    <div class="tl-body">
      <div class="tl-head"><strong>Follow-up sent</strong><span class="tl-time mono">1h ago</span></div>
      <p class="tl-desc">Personalised summary + calendar link sent by SMS.</p>
    </div>
  </li>
  <li class="tl-item tl-now">
    <div class="tl-marker"><span class="tl-dot"></span></div>
    <div class="tl-body">
      <div class="tl-head"><strong>Awaiting reply</strong><span class="tl-time mono">now</span></div>
      <p class="tl-desc">Agent is monitoring the thread for a response.</p>
    </div>
  </li>
  <li class="tl-item tl-next">
    <div class="tl-marker"><span class="tl-dot"></span></div>
    <div class="tl-body">
      <div class="tl-head"><strong>Re-engage in 48h</strong><span class="tl-time mono">scheduled</span></div>
      <p class="tl-desc">If no reply, agent sends a soft nudge with a different angle.</p>
    </div>
  </li>
</ol>
.timeline {
  list-style: none; padding: 0; margin: 0;
  position: relative;
}
.tl-item {
  display: grid; grid-template-columns: 28px 1fr; gap: var(--s-3);
  position: relative;
  padding-bottom: var(--s-5);
}
.tl-item:last-child { padding-bottom: 0; }
.tl-marker {
  position: relative;
  display: flex; justify-content: center;
  padding-top: 4px;
}
.tl-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--fg-faint);
  box-shadow: 0 0 0 3px var(--bg-paper), 0 0 0 4px var(--hair);
  position: relative; z-index: 1;
}
.tl-item::before {
  content: ""; position: absolute;
  left: 13px; top: 18px; bottom: 0;
  width: 1px; background: var(--hair);
}
.tl-item:last-child::before { display: none; }

.tl-done .tl-dot { background: var(--fg); box-shadow: 0 0 0 3px var(--bg-paper), 0 0 0 4px var(--fg); }
.tl-now .tl-dot {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg-paper), 0 0 0 4px var(--accent), 0 0 0 9px var(--accent-soft);
}
.tl-next .tl-dot { background: var(--bg-paper); box-shadow: 0 0 0 3px var(--bg-paper), inset 0 0 0 2px var(--hair); }

.tl-body { padding-top: 0; }
.tl-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-3); }
.tl-head strong { font: 600 14px/1.3 var(--f-display); color: var(--fg); letter-spacing: -0.005em; }
.tl-time { font-size: 12px; color: var(--fg-dim); flex-shrink: 0; }
.tl-desc { font-size: 13.5px; color: var(--fg-soft); margin: 4px 0 0; }

7.9 Code block

Ink surface with a header bar — language pill in pink, filename in muted mono, copy button on the right. Syntax colours are desaturated and warm; the pink keyword picks up the brand accent even in code.

Code snippet

.codeblk

Keeps ink background contained to the block itself — do NOT let ink bleed into surrounding surfaces. Use the mono-uppercase language pill in pink as a small brand hit.

js agents/route.js
const agent = await magicblocks.spawn({
  persona: "SDR",
  channel: "sms",
  goal:    "qualify + book meeting",
});

await agent.handle(lead);
<figure class="codeblk">
  <figcaption>
    <span class="codeblk-lang mono">js</span>
    <span class="codeblk-file mono">agents/route.js</span>
    <button class="codeblk-copy mono">copy</button>
  </figcaption>
  <pre><code><span class="c-k">const</span> <span class="c-v">agent</span> = <span class="c-k">await</span> magicblocks.<span class="c-f">spawn</span>({
  persona: <span class="c-s">"SDR"</span>,
  channel: <span class="c-s">"sms"</span>,
  goal:    <span class="c-s">"qualify + book meeting"</span>,
});

<span class="c-k">await</span> agent.<span class="c-f">handle</span>(lead);</code></pre>
</figure>
.codeblk {
  background: var(--ink); color: var(--paper);
  border-radius: var(--r-lg); overflow: hidden;
  margin: 0; box-shadow: var(--sh-2);
}
.codeblk figcaption {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 10px var(--s-4);
  border-bottom: 1px solid color-mix(in oklab, var(--paper) 10%, transparent);
  background: color-mix(in oklab, var(--paper) 4%, var(--ink));
}
.codeblk-lang {
  padding: 2px 7px; font-size: 10.5px;
  background: var(--accent); color: var(--paper);
  border-radius: var(--r-xs); text-transform: uppercase; letter-spacing: 0.08em;
  font-weight: 600;
}
.codeblk-file { font-size: 12px; color: color-mix(in oklab, var(--paper) 60%, transparent); flex: 1; }
.codeblk-copy {
  background: transparent; border: 1px solid color-mix(in oklab, var(--paper) 20%, transparent);
  color: color-mix(in oklab, var(--paper) 70%, transparent);
  font-size: 11px; padding: 3px 10px; border-radius: var(--r-xs); cursor: pointer;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.codeblk-copy:hover { color: var(--paper); border-color: color-mix(in oklab, var(--paper) 40%, transparent); }
.codeblk pre {
  margin: 0; padding: var(--s-4) var(--s-5);
  font: 13px/1.7 var(--f-mono); color: color-mix(in oklab, var(--paper) 92%, transparent);
  overflow-x: auto;
}
.c-k { color: #FF8BB0; }
.c-v { color: #FFE090; }
.c-f { color: #8CD8FF; }
.c-s { color: #B8F0A6; }

7.10 Stat grid

A row of KPI tiles across the top of a dashboard or an analytics page. Numbers use tabular-nums; deltas use arrow glyph + colour. Responsive: 4 across at desktop, 2 across at tablet, 1 at mobile.

Four-up stat grid

.stat-grid

Each cell is a .stat tile. Label, value, delta. Sits on the warm page with hair borders.

Leads
1,284
↑ 12.4%
Qualified
412
↑ 8.1%
Meetings
87
↓ 3.2%
Revenue
$48.2k
↑ 21.6%
<div class="stat-grid">
  <div class="stat-tile">
    <div class="stat-label">Leads</div>
    <div class="stat-value">1,284</div>
    <div class="stat-delta is-up">↑ 12.4%</div>
  </div>
</div>
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--s-3); width: 100%; }
@media (max-width: 720px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .stat-grid { grid-template-columns: 1fr; } }
.stat-tile { padding: var(--s-4); background: var(--bg-paper);
  border: 1px solid var(--hair); border-radius: var(--r-md); }
.stat-label { font: 500 11px/1 var(--f-mono); text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--fg-dim); }
.stat-value { font: 700 24px/1 var(--f-display);
  font-variant-numeric: tabular-nums; color: var(--fg); margin: var(--s-2) 0; }
.stat-delta { font: 600 12px/1 var(--f-mono); }
.stat-delta.is-up { color: var(--success-text); }
.stat-delta.is-down { color: var(--error-text); }

7.11 Chart

Simple on-brand bar + line charts. Pink for the focus series, lavender for comparison. Grid lines are hair; axis labels are mono small. Drop-in SVG; swap numbers at render.

Bar chart

.chart-bar

7-day pattern. Bars use --accent. Y-axis is implicit via gridlines at 0/50/100.

MTW TFSS
Leads · last 7 days
<figure class="chart-bar">
  <svg viewBox="0 0 320 160">
    <rect x="10" y="80" width="28" height="70" rx="3" fill="var(--accent)"/>
    <!-- … -->
  </svg>
  <figcaption class="chart-cap">Leads · last 7 days</figcaption>
</figure>
.chart-bar { padding: var(--s-4); background: var(--bg-paper);
  border: 1px solid var(--hair); border-radius: var(--r-md); max-width: 420px; }
.chart-cap { font: 400 12px/1.3 var(--f-mono); color: var(--fg-dim);
  margin-top: var(--s-2); text-align: center; }

7.12 Tree

Hierarchy display — file tree, org chart, topic taxonomy. Rows expand/collapse with a chevron; nested children indent. Dotted guide lines keep the relationship visible.

Collapsible tree

.tree

Uses <details>/<summary> for native keyboard + a11y; each branch gets a folder icon, each leaf gets a doc icon.

  • Sales
    • North America
      • Acme Corp
      • Globex
      • Initech
    • Europe
      • Hooli GmbH
      • Umbrella plc
  • Support
    • Open tickets
    • Backlog
<ul class="tree">
  <li><details open>
    <summary><span class="tree-icon">▸</span> Sales</summary>
    <ul>
      <li>Acme Corp</li>
    </ul>
  </details></li>
</ul>
.tree, .tree ul { list-style: none; margin: 0; padding: 0; }
.tree ul { padding-left: var(--s-5); border-left: 1px dashed var(--hair);
  margin-left: var(--s-2); }
.tree summary, .tree li { font: 400 14px/1.8 var(--f-body); color: var(--fg);
  cursor: pointer; padding: 2px 0; list-style: none; }
.tree summary::-webkit-details-marker { display: none; }
.tree-icon { display: inline-block; width: 14px; color: var(--fg-dim);
  transition: transform var(--dur-2) var(--ease); }
.tree details[open] > summary .tree-icon { transform: rotate(90deg); }

7.13 Empty state

What the user sees when a table, list, or feed has nothing to show. Warm icon chip, short title, single-sentence explanation, and ONE primary action + one secondary link.

Table / list empty

.empty

Never leave a surface blank. Always explain why it's empty and give the user a way out. Dashed border reads as 'placeholder' rather than a real record.

No leads yet

Your agent hasn't been routed any leads. Connect a source and your first conversation will appear here.

<div class="empty">
  <div class="empty-ic"><svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg></div>
  <h3 class="empty-title">No leads yet</h3>
  <p class="empty-lede">Your agent hasn't been routed any leads. Connect a source and your first conversation will appear here.</p>
  <div class="empty-actions">
    <a href="#" class="empty-btn">Connect a source</a>
    <a href="#" class="empty-link">Read the quickstart →</a>
  </div>
</div>
.empty {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: var(--s-9) var(--s-5);
  background: var(--bg-paper); border: 1px dashed var(--hair);
  border-radius: var(--r-lg);
  width: 100%;                         /* let it fill its slot in .emp-grid / column */
  max-width: min(640px, 100%);         /* but don't balloon on very wide single-column pages */
  margin: 0 auto;
}
.empty-ic {
  width: 72px; height: 72px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--warm-3);
  color: color-mix(in oklab, var(--ink) 55%, transparent);
  margin-bottom: var(--s-4);
}
.empty-title { font: 600 20px/1.2 var(--f-display); letter-spacing: -0.01em; margin: 0 0 6px; color: var(--fg); }
.empty-lede { font: 400 14.5px/1.55 var(--f-body); color: var(--fg-soft); margin: 0 0 var(--s-5); max-width: 36ch; }
.empty-actions { display: flex; gap: var(--s-4); align-items: center; flex-wrap: wrap; justify-content: center; }
.empty-btn {
  background: var(--accent); color: var(--paper);
  font: 600 13.5px/1 var(--f-display);
  padding: 10px var(--s-4); border-radius: var(--r-md);
  text-decoration: none; box-shadow: var(--sh-pink);
  transition: transform var(--dur-2) var(--ease);
}
.empty-btn:hover { transform: translateY(-1px); color: var(--paper); }
.empty-link { color: var(--fg-soft); font: 500 13.5px/1 var(--f-body); text-decoration: none; }
.empty-link:hover { color: var(--accent-text); }

7.14 Anatomy — table row

The five moving parts that make a data row feel like MagicBlocks. Strip any of these away and it starts to look like every other SaaS table.

Five required parts

1Contact 2 Stage Value
3 AC
Alicia Chen
alicia@northpeak.co
4Qualified 5$48,000
  1. 1
    Mono uppercase header
    11px JetBrains Mono, tracking 0.08em, sunken background. Sort arrow turns pink when active.
  2. 2
    Sort indicator
    Pink chevron on the active column signals direction; grey double-arrow on sortable-but-idle columns.
  3. 3
    Avatar + primary + sub
    32px circle · 14px semibold name · 12px dim email. Person cells always use this triplet.
  4. 4
    Status chip
    One chip per row for stage. Blue = qualified, pink = negotiation, green = won. Don't combine.
  5. 5
    Right-aligned tabular number
    Money and counts right-align so digits stack. 600 weight for emphasis, tabular-nums turns on.

7.15 Score ring

At-a-glance 0–100 score for fit, intent, health, or any band-meaningful metric. Either banded by score range (low/medium/high) or pinned to a metric-specific colour. Four sizes (xs · sm · md · lg) cover inline metadata chips through hero dashboard tiles.

Sizes & bands

.score-ring

Use data-band for semantic colour (low/medium/high) or modifier classes (--accent, --ink, --info) for metric-pinned colours. Stroke length encodes value 0–100. Centre integer; mono uppercase label below.

xs · 28
64 sm · 64
87 md · 87 (high)
72 lg · intent
91 lg · fit
<!-- Banded by score: low (red) · medium (amber) · high (green) -->
<span class="score-ring" data-band="high" aria-label="Score 87">
  <svg viewBox="0 0 36 36">
    <circle class="track" cx="18" cy="18" r="15"/>
    <circle class="fill"  cx="18" cy="18" r="15"
            stroke-dasharray="94.2" stroke-dashoffset="12.2"/>
  </svg>
  <span class="v">87</span>
</span>

<!-- Metric-pinned colour: --accent (intent) · --ink (fit) · --info -->
<span class="score-ring score-ring--lg score-ring--accent">
  <svg viewBox="0 0 36 36">...</svg>
  <span class="v">72</span>
</span>
/* The fill stroke-dashoffset = (1 - score/100) * circumference.
   Circle r=15 in a 36×36 box → circumference ≈ 94.2.
   So 87% → dashoffset 94.2 × (1 - 0.87) = 12.2. */
.score-ring { --sr-size: 40px; --sr-stroke: 4px; --sr-fill: var(--accent); }
.score-ring--xs { --sr-size: 16px; --sr-stroke: 2px; }
.score-ring--sm { --sr-size: 24px; --sr-stroke: 3px; }
.score-ring--lg { --sr-size: 64px; --sr-stroke: 5px; }
.score-ring[data-band="low"]    { --sr-fill: var(--score-low); }
.score-ring[data-band="medium"] { --sr-fill: var(--score-medium); }
.score-ring[data-band="high"]   { --sr-fill: var(--score-high); }

7.16 SLA countdown ring

Time-to-breach indicator for tickets and customer-success queues. Fill grows clockwise as elapsed-fraction grows; colour ramps green → amber → red as the deadline approaches. On breach, gentle shake (skipped under reduced motion). Three sizes: sm (inline), md (card), lg (ticket page hero).

Sizes & states

.sla-ring

Set data-state to ok (<50% used) · warn (50–80%) · danger (80%+) · breach. Centre text holds remaining time or "BREACHED". Live-update the dasharray every 30s in the consumer.

sm · ok
1h 23m
md · warn
11m
md · danger
BREACHED
lg · breach
<span class="sla-ring" data-state="warn">
  <svg viewBox="0 0 36 36">
    <circle class="track" cx="18" cy="18" r="15"/>
    <circle class="fill"  cx="18" cy="18" r="15"
            stroke-dasharray="94.2" stroke-dashoffset="32"/>
  </svg>
  <span class="t">1h 23m</span>
</span>

<!-- breach state animates a shake (no animation under reduced-motion) -->
<span class="sla-ring sla-ring--lg" data-state="breach">
  <svg viewBox="0 0 36 36">...</svg>
  <span class="t">BREACHED</span>
</span>
.sla-ring[data-state="ok"]     { --sla-fill: var(--success); }
.sla-ring[data-state="warn"]   { --sla-fill: var(--warning); }
.sla-ring[data-state="danger"] { --sla-fill: var(--error); }
.sla-ring[data-state="breach"] { --sla-fill: var(--error);
  animation: sla-shake 0.4s var(--ease) 0s 1; }
@media (prefers-reduced-motion: reduce) {
  .sla-ring[data-state="breach"] { animation: none; }
}

/* Live update: in JS, set --sla-fill and the fill circle's
   stroke-dashoffset every 30s based on elapsed/total. */

7.17 Health sparkline + risk badge

Tiny inline trend (90-day default) for company health, NPS, MRR, account heat, etc. No axes, no gridlines, just the line + an end-dot. Pairs with a risk badge that encodes the same colour band as a label. Three sizes: inline (12px tall, list-row use), card (40px), page (full width 120px with axis labels in the consumer).

Sparkline + risk badge

.spark · .risk-badge

Stroke colour follows data-risk. Stroke width auto-bumps in dark mode (1.2px → 1.5px). Always pair with the risk badge in lists so the colour reads explicitly, not just as ambient tone.

BR
BlueRock Health
healthcare · ent
Healthy · 87
NP
Northpeak Logistics
logistics · mid
At risk · 52
SK
Skyhook Manufacturing
industrial · sm
Critical · 18
90-day health
87
90d agotoday
<!-- Inline sparkline + risk badge (use side-by-side in list rows) -->
<span class="spark spark--inline" data-risk="low">
  <svg viewBox="0 0 64 12" preserveAspectRatio="none">
    <polyline class="line" points="1,8 8,9 14,7 21,8 28,5 35,6 42,4 49,3 56,2 63,2"/>
    <circle class="end-dot" cx="63" cy="2" r="1.6"/>
  </svg>
</span>
<span class="risk-badge" data-risk="low">Healthy · 87</span>

<!-- Risk levels: none · low · medium · high · critical -->
.spark[data-risk="low"]      { --spark-color: var(--score-low); }
.spark[data-risk="medium"]   { --spark-color: var(--score-medium); }
.spark[data-risk="high"]     { --spark-color: var(--score-high); }
.spark[data-risk="critical"] { --spark-color: var(--score-high); }
.spark .line { stroke: var(--spark-color);
  stroke-width: var(--spark-stroke); /* 1.2px light, 1.5px dark */ }

.risk-badge[data-risk="low"]      { background: var(--badge-bg-success);
  color: var(--success-text); }
.risk-badge[data-risk="medium"]   { background: var(--badge-bg-warning);
  color: var(--warning-text); }
.risk-badge[data-risk="high"]     { background: var(--badge-bg-danger);
  color: var(--error-text); }

7.18 Stat tile — moment + sparkline-behind

Two extensions of the existing .stat-tile primitive (7.10): the moment variant for hero KPIs that need to dominate (deep ink bg, accent number), and the sparkline-behind variant for ambient trend context without taking up extra real estate.

Variants

.stat-tile--moment · .stat-tile--spark

Reach for the moment variant when ONE number is the headline of a dashboard ("$1.2M ARR this quarter"). Pair with the spark variant when the trend is as important as the value. Both honour the existing 4-up .stat-grid layout.

Open tickets
87
↓ 12 vs last week
Avg first response
4m 12s
↑ within SLA
Net new ARR · this quarter
$1.2M
↑ 24% YoY
Pipeline forecast
$3.8M
↑ 11% MoM
<!-- Moment variant: ink bg, accent number -->
<div class="stat-tile stat-tile--moment">
  <div class="stat-label">Net new ARR · this quarter</div>
  <div class="stat-value">$1.2M</div>
  <div class="stat-delta is-up">↑ 24% YoY</div>
</div>

<!-- Sparkline-behind variant: ambient trend at the bottom -->
<div class="stat-tile">
  <div class="stat-label">Open tickets</div>
  <div class="stat-value">87</div>
  <div class="stat-delta is-down">↓ 12 vs last week</div>
  <span class="spark stat-spark spark--inline" data-risk="low">...</span>
</div>
.stat-tile--moment { background: var(--ink); color: var(--paper);
  border-color: rgba(244, 236, 228, 0.12); }
.stat-tile--moment .stat-label { color: rgba(244, 236, 228, 0.65); }
.stat-tile--moment .stat-value { color: var(--accent-text);
  font-size: 36px; font-weight: 700; }

/* Sparkline as ambient background — bottom-right, low opacity */
.stat-tile { position: relative; overflow: hidden; }
.stat-tile .stat-spark { position: absolute; right: 0; bottom: 0;
  left: 40%; height: 50%; opacity: 0.18; pointer-events: none; }