Nº 233 of 520
Editorial creator profile card
A 440px creator card with a printed-issue cover, an overlapping initials avatar, stats that count up on load, a Follow/Following toggle and a mutuals row.
Preview
Use it
Free to use · credit appreciated1 Once, in your project
npx skills add SusanAcharya/Design-Lounge 2 Then ask
Using the Design Lounge skill, build "Editorial creator profile card" (piece social-profile-card) 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.
<!-- Design Lounge Nº 233 · "Editorial creator profile card" · designlounge.vercel.app -->
# Editorial creator profile card
> **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 profile card of a writer on "Thatch", an invented newsletter-and-essays platform. It sits in a sidebar, a hover preview or a "Who to follow" rail. The cover reads like the masthead of a printed issue: an oxblood block with a small-caps issue line, a two-line italic serif kicker and a huge ghosted italic "41" bleeding off the bottom-right edge. An 88px ochre avatar with italic initials overlaps the cover. Below it come the name, handle, bio, three stats in hairline columns, the latest letter, and a mutuals row. The detail worth copying is how quiet the motion is. The stats count up once on load with a quartic ease-out, and following someone ticks the follower count by exactly one with the same counter. No confetti, no bounce.
## Reference behaviour
1. Initial state: the card is centred on a warm paper page ruled with faint 32px horizontal lines. Stats show 0 and count up to 48,213 / 312 / 141 over 1100ms each, staggered by 90ms, starting 120ms after load.
2. The Follow button is a 40px ink pill with a plus icon and the word "Follow". `aria-pressed="false"`.
3. Click Follow. The button becomes outlined (transparent fill, ink border, ink text), the icon becomes a check and the label reads "Following". `aria-pressed="true"`. The follower count animates from 48,213 to 48,214 over 380ms. A polite live region says "You now follow Juno Achterberg".
4. Hover the button while following. Label swaps to "Unfollow", the check hides, and text and border turn oxblood `#8C2F1B`. This is the confirmation affordance. It is not a second button.
5. Click again to unfollow. Back to the filled ink pill, count 48,214 → 48,213, live region "You unfollowed Juno Achterberg".
6. Hover the "Latest" title. A 1px oxblood underline grows from left to right over 300ms.
7. Hover the mutuals row. The second and third face fan out by 4px and 8px over 200ms, as if the stack loosened.
8. Press on the button scales it to 0.96 for 120ms.
9. Reduced motion: counters render final values immediately, and all transitions are removed.
## Structure
```
page 1280 × 800, paper #ECE5D8 with 32px rule lines, card centred
┌──────────────── card 440 wide, radius 6, 1px #DDD3C4 ────────────────┐
│ COVER 176 tall, #8C2F1B, padding 18/24 │
│ LETTERS FROM THE EDGE VOL. 4 │
│ Field notes on slow cities (Fraunces italic 24) │
│ and who keeps them ╱41 ghosted │
│ ┌────┐ │
├──│ Ja │────────────────────────────────────────── [ + Follow ] ──────┤
│ └────┘ 88px, −44px overlap, 4px card-colour ring, green dot │
│ Juno Achterberg Fraunces 600 30 │
│ @juno.writes · Rotterdam · on Thatch since 2021 13px muted │
│ Urbanist and essayist. I walk a city until it tells me… max 36ch │
│ ──────────────────────────────────────────────────────────────────── │
│ 48,213 │ 312 │ 141 │
│ FOLLOWERS │ FOLLOWING │ LETTERS │
… 170 more lines. Copy or download for the full brief. Loading the source…Brief
210 linesBuild 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 profile card of a writer on “Thatch”, an invented newsletter-and-essays platform. It sits in a sidebar, a hover preview or a “Who to follow” rail. The cover reads like the masthead of a printed issue: an oxblood block with a small-caps issue line, a two-line italic serif kicker and a huge ghosted italic “41” bleeding off the bottom-right edge. An 88px ochre avatar with italic initials overlaps the cover. Below it come the name, handle, bio, three stats in hairline columns, the latest letter, and a mutuals row. The detail worth copying is how quiet the motion is. The stats count up once on load with a quartic ease-out, and following someone ticks the follower count by exactly one with the same counter. No confetti, no bounce.
Reference behaviour
- Initial state: the card is centred on a warm paper page ruled with faint 32px horizontal lines. Stats show 0 and count up to 48,213 / 312 / 141 over 1100ms each, staggered by 90ms, starting 120ms after load.
- The Follow button is a 40px ink pill with a plus icon and the word “Follow”.
aria-pressed="false". - Click Follow. The button becomes outlined (transparent fill, ink border, ink text), the icon becomes a check and the label reads “Following”.
aria-pressed="true". The follower count animates from 48,213 to 48,214 over 380ms. A polite live region says “You now follow Juno Achterberg”. - Hover the button while following. Label swaps to “Unfollow”, the check hides, and text and border turn oxblood
#8C2F1B. This is the confirmation affordance. It is not a second button. - Click again to unfollow. Back to the filled ink pill, count 48,214 → 48,213, live region “You unfollowed Juno Achterberg”.
- Hover the “Latest” title. A 1px oxblood underline grows from left to right over 300ms.
- Hover the mutuals row. The second and third face fan out by 4px and 8px over 200ms, as if the stack loosened.
- Press on the button scales it to 0.96 for 120ms.
- Reduced motion: counters render final values immediately, and all transitions are removed.
Structure
page 1280 × 800, paper #ECE5D8 with 32px rule lines, card centred
┌──────────────── card 440 wide, radius 6, 1px #DDD3C4 ────────────────┐
│ COVER 176 tall, #8C2F1B, padding 18/24 │
│ LETTERS FROM THE EDGE VOL. 4 │
│ Field notes on slow cities (Fraunces italic 24) │
│ and who keeps them ╱41 ghosted │
│ ┌────┐ │
├──│ Ja │────────────────────────────────────────── [ + Follow ] ──────┤
│ └────┘ 88px, −44px overlap, 4px card-colour ring, green dot │
│ Juno Achterberg Fraunces 600 30 │
│ @juno.writes · Rotterdam · on Thatch since 2021 13px muted │
│ Urbanist and essayist. I walk a city until it tells me… max 36ch │
│ ──────────────────────────────────────────────────────────────────── │
│ 48,213 │ 312 │ 141 │
│ FOLLOWERS │ FOLLOWING │ LETTERS │
│ ──────────────────────────────────────────────────────────────────── │
│ Latest The bench as infrastructure (italic serif 17) │
│ (MS)(TB)(RA) Followed by Mira Sato, Teo Brandt and 14 others… │
└──────────────────────────────────────────────────────────────────────┘
article.cardlabelled by theh1name.- Cover is decorative (
aria-hidden="true"). It contains the issue line, the kickerp, and the ghost numeralspan. .rowholds the avatar (decorative initials) and the followbuttonaligned to its bottom edge.- Stats are a
dlwith threedivgroups. Eachdtis visually hidden and the visible uppercase label isaria-hiddento avoid double reading. - “Latest” is a
pwith a link. - Mutuals are a decorative face stack plus a
pwith twostrongnames. - One visually hidden
p aria-live="polite"for follow announcements.
Tokens
:root {
--bg: #ece5d8; /* page paper */
--card: #fbf8f2; /* card surface */
--ink: #1f1a17; /* primary text, filled button */
--ink-2: #4a423b; /* bio */
--ink-3: #6f665d; /* meta, labels */
--line: #ddd3c4; /* hairlines, card border */
--accent: #8c2f1b; /* oxblood: cover, focus, unfollow hover, emphasis */
--accent-ink: #f6e9dc; /* text on cover */
--ochre: #d9a441; /* avatar */
--online: #3f7a4a; /* presence dot */
--serif: "Fraunces", Georgia, serif;
--sans: "Instrument Sans", system-ui, sans-serif;
--r: 6px;
--pill: 999px;
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px;
--shadow-card: 0 1px 0 rgba(31,26,23,.04), 0 24px 48px -28px rgba(60,36,20,.35);
--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
--expo: cubic-bezier(0.16, 1, 0.3, 1);
--t-micro: 180ms;
--t-count: 1100ms;
--t-tick: 380ms;
}
Typography
| Role | Family | Size / line | Weight | Tracking | Notes |
|---|---|---|---|---|---|
| Issue line | Instrument Sans | 11px | 600 | 0.14em | uppercase, --accent-ink |
| Kicker | Fraunces italic | 24 / 1.12 | 400 | 0 | opsz 48, max-width 270px |
| Ghost numeral | Fraunces italic | 150 / 1 | 400 | −0.06em | rgba(246,233,220,.16), opsz 144 |
| Avatar initials | Fraunces italic | 34px | 600 | −0.04em | “Ja”, mixed case on purpose |
| Name | Fraunces | 30 / 1.05 | 600 | −0.02em | opsz 72 |
| Handle | Instrument Sans | 13px | 400 | 0 | --ink-3 |
| Bio | Instrument Sans | 15 / 1.5 | 400 | 0 | --ink-2, 36ch |
| Bio emphasis | Fraunces italic | 16px | 400 | 0 | --accent |
| Stat number | Fraunces | 26 / 1 | 400 | −0.02em | tabular lining numerals |
| Stat label | Instrument Sans | 11px | 600 | 0.12em | uppercase |
| Latest title | Fraunces italic | 17 / 1.25 | 400 | 0 | |
| Button | Instrument Sans | 14px | 600 | 0 | |
| Mutual initials | Instrument Sans | 9px | 600 | 0.02em |
Use font-variant-numeric: tabular-nums lining-nums on stat numbers so the count-up does not wobble horizontally.
Motion
| Thing | Trigger | Property | From → to | Duration | Easing | Reduced motion |
|---|---|---|---|---|---|---|
| Stat counters | load | text value | 0 → target | 1100ms, stagger 90ms, delay 120ms | quartic out 1-(1-p)^4 | final values at once |
| Follower tick | follow toggle | text value | n → n±1 | 380ms | quartic out | instant |
| Button fill | aria-pressed | background, color | ink fill ↔ transparent | 180ms | --ease | none |
| Button press | :active | transform | scale 1 → .96 | 120ms | --ease | none |
| Latest underline | hover/focus | background-size | 0 → 100% 1px | 300ms | --expo | none |
| Mutual fan | row hover | translateX | 0 → 4px / 8px | 200ms | --expo | none |
States
- Follow resting:
--inkfill,--cardtext, plus icon, “Follow”. Hover darkens the fill to#3a312b. - Following: transparent fill, 1px
--inkborder, check icon, “Following”. - Following + hover: “Unfollow”, no icon, text and border
--accent. - Focus-visible everywhere: 2px
--accentoutline, offset 3px. - Presence: 14px
--onlinedot, bottom-right of avatar, 3px card-colour ring. - Loading: not shown. If data is loading, render the card frame with stat numbers as ”—”, not skeleton bars.
- Error: not part of this piece.
Accessibility
buttonwitharia-pressed. The visible label changes too (“Follow” / “Following”), so screen-reader and sighted users get the same state.- The hover-only “Unfollow” label is a visual cue. The accessible name stays “Following” with pressed=true, which is correct.
- Stats are a
dl. Visible labels arearia-hiddenand hiddendts carry the names. - The live region announces follow/unfollow once. It does not announce the counter animation.
- Contrast:
#6f665don#fbf8f2≈ 5.3:1.#f6e9dcon#8c2f1b≈ 8:1. - Hit targets: button 40px tall, min 128px wide.
- Tab order: follow button → latest link.
Responsive rules
- ≥1280 and 1024: card stays 440px, centred.
- 768: unchanged.
- <640: card is
min(440px, 100%)with 16px page padding. At 375 the stats keep three columns, labels stay one line, and the mutuals text wraps to two lines. - Never truncate the name. Allow it to wrap.
Acceptance checklist
Always
- Cover is a solid accent block with an issue line, a two-line italic kicker and a ghosted numeral, with no image.
- Avatar is 88px and overlaps the cover by exactly half (−44px) with a 4px ring in the card colour.
- Follow button is 40px tall with
aria-pressed, and its label changes between Follow and Following. - Hovering the followed button shows Unfollow in the accent colour.
- Stats are three equal columns split by 1px hairlines, top and bottom rules included.
- Counters use tabular numerals and quartic ease-out, and run once on load.
- Following changes the follower count by exactly one, animated.
- A polite live region announces follow changes.
- Reduced motion shows final numbers immediately.
- No horizontal scroll at 375px.
This demo
- Name “Juno Achterberg”, handle “@juno.writes · Rotterdam · on Thatch since 2021”.
- Stats 48,213 Followers, 312 Following, 141 Letters.
- Cover reads “LETTERS FROM THE EDGE · VOL. 4” and “Field notes on slow cities and who keeps them”.
- Latest letter “The bench as infrastructure”.
- Mutuals: MS, TB, RA faces, “Followed by Mira Sato, Teo Brandt and 14 others you follow”.
Implementation notes
The counter. Use one function for both the load count-up and the follow tick, driven by requestAnimationFrame:
const fmt = n => n.toLocaleString('en-US');
function count(el, from, to, ms) {
if (reduce) { el.textContent = fmt(to); return; }
const t0 = performance.now();
const step = t => {
const p = Math.min(1, (t - t0) / ms), e = 1 - Math.pow(1 - p, 4);
el.textContent = fmt(Math.round(from + (to - from) * e));
if (p < 1) requestAnimationFrame(step);
};
requestAnimationFrame(step);
}
Keep the true value in data-to and read it before animating. Do not parse the displayed text, because mid-animation it is wrong.
The three-state button is all CSS on aria-pressed plus :hover:
.follow[aria-pressed="true"] { background: transparent; color: var(--ink); }
.follow[aria-pressed="true"]:hover { color: var(--accent); border-color: var(--accent); }
.follow .alt { display: none; }
.follow[aria-pressed="true"]:hover .lbl { display: none; }
.follow[aria-pressed="true"]:hover .alt { display: inline; }
Give the button a min-width (128px) so “Follow” → “Following” → “Unfollow” never changes its width and nudges the layout.
The ghost numeral is a span absolutely positioned at right: 10px; bottom: -22px with overflow: hidden on the cover, so it is cut by the cover edge like a printed bleed.
Common mistakes:
- Animating the counter with a linear ease. It reads as a slot machine.
- Bouncing or spring-scaling the button on follow.
- A stock photo cover. The cover is typographic.
- Putting a drop shadow under the avatar instead of the card-coloured ring.
- Using the serif for the button or the labels.
- Announcing every counter frame to assistive tech.
Details
- Palette
- Type
- Fraunces · Instrument Sans
- Motion
- Subtle motion
- Build
- Quick build
- Tags
On the shelves