Design Lounge
Install

Nº 555 of 605

Agent at work hero

A hero for an invented reconciliation agent that shows a labelled example run: a five-step plan ticking off, tool calls and results scrolling, a journal diff, and a status line.

Preview

Open full size
1280 × 800 · 12.8 KB · 174 lines

Use it

Free to use · credit appreciated

1 Once, in your project · Node 22.20+

npx skills add SusanAcharya/Design-Lounge

2 Then ask

Using the Design Lounge skill, build "Agent at work hero" (piece hero-agent-at-work) in my stack. Match its brief; restyle it onto my product's theme.

No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.

Brief

174 lines

Build brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them.

What it is

The top of a site for Ledgerline, an invented agent that reconciles a company’s bank feed against its open invoices. The headline names the job (“Matches every bank line to its invoice. Then shows you why.”) and the right half shows the agent doing it, in a panel plainly tagged “Example run”: the task as a person wrote it, a five-step plan that ticks off, a log of tool calls and their results, a drafted journal entry as a diff, and a status line that ends on “Waiting for approval … no writes yet”. It is honest about what an agent does: the copy and the run both say nothing is posted until a person approves. The detail worth copying is that the first frame is already mid-run, so the panel reads as work in progress rather than an empty terminal.

Reference behaviour

  1. Initial state: step 1 (“Pull 1,284 lines from the bank feed”) is done, step 2 (“Match against 412 open invoices”) is spinning, steps 3–5 are idle. The log already shows ten lines (bank fetch, open invoices, match rules, two matches, each with its result) and the status reads “Step 2 of 5 · 1,031 of 1,284 matched” with the bar at 52%.
  2. The run continues on its own clock: 1.8s after load a card spend with no invoice is flagged (status 1,236, 68%), then step 3 starts (flag six lines), then step 4 (draft journal JE-1031 shown as a green + Dr line and a red - Cr line), each 1.1–1.3s apart. The status text and bar update with each event; the bar width eases over 600ms.
  3. Final state, about 5.4s after load: steps 1–4 done (green filled circle with a check), step 5 (“Wait for approval, then post”) shows a dashed amber ring, the status dot turns amber and stops pulsing, and the status reads “Waiting for approval · 4 entries · 6 flags · 3m 12s · no writes yet”. The run then holds; it never loops by itself.
  4. New log lines fade and rise 6px over 280ms (expo out) and push older lines up; the log keeps at most 26 lines.
  5. “Replay” in the panel header clears the plan and log and plays every event from the start at 120ms per instant event plus each event’s delay (full run about 8s).
  6. Hover the primary buttons: brightness 1.08; ghost buttons: ring goes from #5D6A78 to --ink.
  7. Reduced motion: the final state is rendered at once, no spinner, no pulse, no line animation. Replay redraws the final state.

Structure

1280 × 800
┌──────────────────────────────────────────────────────────────────────┐
│ ≡ Ledgerline            How it works  Controls  Integrations  Pricing [Book a walkthrough] │ nav 64
├─────────────────────────────────────┬────────────────────────────────┤
│ Reconciliation agent for finance…   │ [Example run] Harbor & Pine…  [↻ Replay] │ 12/16
│                                     ├────────────────────────────────┤
│ Matches every                        │ task sentence 14px            │
│ bank line to its      60/1.02        │ started 06:02 by Priya Anand…  │
│ invoice. Then shows                  ├──────────┬─────────────────────┤
│ you why.  (second sentence ink-2)    │ ✓ Pull…  │ > bank.fetch(…)     │
│ lede 17/1.6, max 470                 │ ◌ Match… │   1,284 lines · …   │
│ [Run it on last month →] [Read the…] │ ○ Flag…  │ > match(line=841…)  │
│ ─────────────────────────            │ ○ Draft… │   INV-2291 …        │
│ 96.1%          4 h                   │ ○ Wait…  │ + Dr 6810 …  - Cr … │
│                                      ├──────────┴─────────────────────┤
│                                      │ • Step 2 of 5 · 1,236 …  ▬▬▬▬░ │ status
└─────────────────────────────────────┴────────────────────────────────┘
grid: 1fr | 620px, gap 56, padding 40 48; panel max-height 640, plan column 236px
  • <nav aria-label="Primary">: logo link, four links, small accent button.
  • <section class="hero" aria-labelledby="h">
    • Copy div: mono eyebrow p, h1 (second sentence in a span), lede, button row, .facts with two figures.
    • .run[role=region][aria-label="Example run of the agent"]: .rhead (tag, run title, Replay button), .task (p + small), .body grid with ol.plan and .log[aria-hidden], .status[role=status][aria-live=polite] with dot, text, bar.

Tokens

:root {
  --bg: #0f1216;        /* page */
  --panel: #151a20;     /* run panel */
  --panel-2: #1b2129;   /* status bar */
  --line: #262e38;      /* hairlines */
  --line-2: #34404d;    /* tag border, bar track */
  --ink: #e9edf1;
  --ink-2: #9aa6b2;     /* secondary, results */
  --ink-3: #7f8b97;     /* idle plan steps, meta */
  --ring: #5d6a78;      /* ghost buttons, idle step rings */
  --accent: #6cb6ff;    /* calls, spinner, bar, primary button */
  --accent-ink: #06223d;
  --add: #7fd19b;       /* done steps, + lines */
  --del: #f2857a;       /* - lines */
  --warn: #f0c36a;      /* example tag, flags, waiting */
  --sans: "Geist", system-ui, sans-serif;
  --mono: "Geist Mono", ui-monospace, monospace;
  --fs-h1: 60px; --fs-lede: 17px; --fs-fact: 22px; --fs-body: 14px; --fs-plan: 13px; --fs-mono: 12px;
  --r-panel: 14px; --r-btn: 8px; --r-tag: 4px;
  --space: 4px 8px 10px 12px 14px 16px 18px 28px 36px 40px 48px 56px;
  --shadow-panel: 0 40px 80px -40px rgba(0, 0, 0, .6);
  --ease: cubic-bezier(.2, .7, .2, 1);
  --expo: cubic-bezier(.16, 1, .3, 1);
  --t-micro: 160ms; --t-line: 280ms; --t-bar: 600ms;
}

Typography

RoleFamilySizeWeightLine-heightTrackingNotes
h1Geist60px (50 under 1180; clamp(36px,10vw,52px) phone)6001.02-0.035emsecond sentence --ink-2
LedeGeist17px400, last sentence 500 ink1.60
FactsGeist22px over 13px500 / 4001.1 / 1.5-0.02em
LogoGeist16px60010
Task, buttons, navGeist14px400 / 6001.50
Plan stepsGeist13px4001.40
Eyebrow, header, log, statusGeist Mono12px400 / 5001.60.02em eyebrow> prefix on calls

Motion

ThingTriggerPropertyFrom → toDurationEasingReduced motion
Log lineeventopacity, translateY0, 6px → 1, 0280msexpo outnone
Spinnerstep runningrotate0 → 360°900ms looplinear (spinner)static ring
Plan step colourstep changecolorink-3 → ink → ink-2280msstandardinstant
Progress barstatus eventwidthprevious → new %600msexpo outinstant
Status dotrunningopacity1 → .35 → 11.4s loopstandardstatic
Event clockloadsequence15 events instant, then 600ms + 1.1–1.3s gaps≈5.4sn/afinal state
Replayclicksequencefrom empty≈8sn/afinal state

States

  • Step idle: 16px ring --ring, text --ink-3. Running: accent ring with a transparent right edge, spinning; text --ink. Done: filled --add with a dark check; text --ink-2. Waiting: dashed --warn ring; text --ink.
  • Log line kinds: call (accent, > prefix), result (ink-2, 14px indent), flag (warn, indented), journal header (ink), add (green on 8% green), del (red on 8% red).
  • Status running: pulsing accent dot. Holding: amber dot, no pulse, bar full.
  • Replay button: 1px --ring border; hover border --ink.
  • Focus-visible: 2px accent outline, 3px offset.

Accessibility

  • The panel is a labelled region; the visual log is aria-hidden because it changes quickly. The status line is role="status" with aria-live="polite", so a screen reader hears each step summary, not every tool call.
  • The plan is an ordered list; state is visible in text colour and icon shape, and the status line repeats it in words.
  • “Example run” is a visible tag, not hover text, so nobody mistakes the panel for their own data.
  • Contrast on --panel: ink 14.6:1, ink-2 7.0:1, ink-3 5.0:1, accent 8.3:1, warn 11:1, add 10:1, del 7.2:1. Ghost rings #5D6A78 are 3.1:1 on the page.
  • Tab order: logo, four nav links, Book a walkthrough, Run it on last month, Read the audit trail spec, Replay.

Responsive rules

  • ≥1280: as drawn.
  • 1180: panel 540px, plan column 200px, h1 50px, gap 40px.
  • 900–1180: same two columns.
  • <900 (phone at 390): body scrolls; one column with copy first and the panel below; the plan sits above the log (full width, hairline under it); the log is 240px tall; the header’s spacer hides and the tag never wraps. No sideways scroll: log lines use pre-wrap and break-word, and calls are written short enough (≤ 46 characters) to stay on one line at 1280.

Acceptance checklist

Always

  • The headline names the job the agent does, in plain words.
  • The run panel carries a visible “Example run” tag.
  • The first frame is mid-run: at least one step done, one running, and a filled log.
  • The run ends on a waiting-for-approval state and does not loop by itself; Replay restarts it.
  • Copy and the final status both say nothing is written before a person approves.
  • The log is aria-hidden; the status line is a polite live region.
  • Unfilled controls (ghost buttons, Replay) have rings of at least 3:1.
  • Reduced motion renders the final state immediately.
  • No horizontal scroll at 390 wide.

This demo

  • Plan has five steps from “Pull 1,284 lines from the bank feed” to “Wait for approval, then post”.
  • Log includes bank.fetch("CB-0193", month="2026-10"), three match(…) calls, one flag([…]) with six line numbers, and JE-1031 as a + Dr 6810 / - Cr 1010 pair for €48.50.
  • Status ends “Waiting for approval · 4 entries · 6 flags · 3m 12s · no writes yet”.
  • Facts read “96.1%” and “4 h”.

Implementation notes

One event list drives everything. Each entry is [delayMs, kind, payload]; the same apply() renders the first frame, the timed run and the reduced-motion final state:

const E = [[0,'step',0], [0,'call','bank.fetch("CB-0193", month="2026-10")'], /* … */
           [1300,'step',4], [0,'hold','Waiting for approval · 4 entries · 6 flags · 3m 12s · no writes yet',100]];
function run() {
  let i = 0, t = 0;
  for (; i < E.length && i < 15; i++) apply(E[i]);          // first frame is already mid-run
  for (; i < E.length; i++) { t += E[i][0]; const e = E[i]; timers.push(setTimeout(() => apply(e), t + 600)); }
}

Bottom-anchored log. Flex column with justify-content: flex-end and hidden overflow; new lines append at the end and old ones fall off the top. Cap the node count:

.log { display: flex; flex-direction: column; justify-content: flex-end; overflow: hidden; }
.ln  { animation: in 280ms cubic-bezier(.16,1,.3,1) both; white-space: pre-wrap; word-break: break-word; }
@keyframes in { from { opacity: 0; transform: translateY(6px); } }

Plan icons from one element. The same i is a ring, a spinner (transparent right border plus rotation), a filled check (pseudo-element tick) or a dashed wait ring, chosen by the li class.

Common mistakes: an empty terminal on first paint; logs that loop forever and read as fake; tool calls so long they wrap into unreadable fragments; a mask fade on the log that drops old lines below contrast; announcing every log line to screen readers.

Details

Palette
Type
Geist · Geist Mono
Motion
Subtle motion
Build
One session
Designed bySusan AcharyaKathmandu

Studied

Linear

Show the product doing the work. Fade it at the edges and keep one colour for what matters.

All sources