Nº 122 of 520
Long-form product case study
A product designer's case study page: italic serif hero with a phone mockup, role and timeline facts, sketches that draw themselves, count-up outcome metrics, quote and next project.
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 "Long-form product case study" (piece portfolio-case-study-long) 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º 122 · "Long-form product case study" · designlounge.vercel.app -->
# Long-form product case study
> **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
One case study from the portfolio of Noor Halabi, a fictional product designer: "Ebb", a ferry-pass app for Kelda Ferries. The page reads like a long magazine feature on a soft sage ground: a 250px italic serif title, a phone mockup floating over a gradient fjord, a four-column facts strip, then numbered sections (Problem, Process, Outcome) with sticky side labels, three hand-drawn SVG sketches that draw themselves on scroll, count-up metrics, a coral pull-quote card and a large next-project link. The detail worth copying is the restraint of the system: one serif, one sans, one coral accent, a 3/9 column split that never changes, and motion only where it explains something (sketches drawing, numbers arriving).
## Reference behaviour
1. Initial state (scrollTop 0): sticky 60px bar, hero with eyebrow, "Ebb", lede, the phone art card, and the facts strip all inside the first 800px.
2. A 2px coral progress line along the bar's bottom edge grows from 0 to 100% width as the page scrolls.
3. Scroll to Problem: left column shows "01" (64px coral serif) over the uppercase label; it is `position:sticky; top:84px` so it stays beside the text while the section scrolls.
4. Scroll to Process: when the sketch row is 35% visible, all strokes in the three SVG sketches draw in over 1400ms (stroke-dashoffset to 0). Accent shapes are coral and 2.2px; the rest are ink and 1.6px.
5. Clicking the sketch row replays the drawing (dashoffset resets with transitions disabled for one frame, then draws again).
6. Scroll to Outcome: when the metric row is 35% visible, four numbers count up over 1200ms with ease-out-quart: −38%, 61%, 4.8, 212k. Suffixes render at 32px next to the 72px figure.
7. Below: a coral-tint quote card, then the "Next case study" band. Hovering it moves the round arrow button 8px left and rotates it −45° over 360ms.
8. The "Next project" link in the bar smooth-scrolls to the band.
## Structure
```
1280 × 800 (56px side padding)
┌──────────────────────────────────────────────────────────────────────┐
│ Noor Halabi Case study 04/06 Work About Notes Next project │ 60 sticky
│▔▔▔▔▔ 2px coral progress │
├──────────────────────────────────────────┬───────────────────────────┤
│ • Kelda Ferries · iOS & Android · 2025 │ ┌───────────────────────┐ │
│ │ │ fjord gradient sun │ │
│ Ebb (250px italic Literata, teal) │ │ ┌─phone 236×480─┐ │ │ art card 500 tall, r22
│ │ │ │ ticket + QR │ │ │
│ Making the 07:40 to Holm feel like a │ │ │ Hold to board │ │ │
│ habit, not a hassle. (34px, 17ch) │ └─────┴───────────────┴─┘ │
├──────────┬──────────┬──────────┬─────────┴───────────────────────────┤ 1px ink rule
│ ROLE │ TIMELINE │ TEAM │ SHIPPED │ facts
└──────────┴──────────┴──────────┴─────────────────────────────────────┘
below the fold (each section is a 3fr / 9fr grid, 96px top padding):
01 Problem │ h3 44px + two paragraphs (62ch)
… 166 more lines. Copy or download for the full brief. Loading the source…Brief
206 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
One case study from the portfolio of Noor Halabi, a fictional product designer: “Ebb”, a ferry-pass app for Kelda Ferries. The page reads like a long magazine feature on a soft sage ground: a 250px italic serif title, a phone mockup floating over a gradient fjord, a four-column facts strip, then numbered sections (Problem, Process, Outcome) with sticky side labels, three hand-drawn SVG sketches that draw themselves on scroll, count-up metrics, a coral pull-quote card and a large next-project link. The detail worth copying is the restraint of the system: one serif, one sans, one coral accent, a 3/9 column split that never changes, and motion only where it explains something (sketches drawing, numbers arriving).
Reference behaviour
- Initial state (scrollTop 0): sticky 60px bar, hero with eyebrow, “Ebb”, lede, the phone art card, and the facts strip all inside the first 800px.
- A 2px coral progress line along the bar’s bottom edge grows from 0 to 100% width as the page scrolls.
- Scroll to Problem: left column shows “01” (64px coral serif) over the uppercase label; it is
position:sticky; top:84pxso it stays beside the text while the section scrolls. - Scroll to Process: when the sketch row is 35% visible, all strokes in the three SVG sketches draw in over 1400ms (stroke-dashoffset to 0). Accent shapes are coral and 2.2px; the rest are ink and 1.6px.
- Clicking the sketch row replays the drawing (dashoffset resets with transitions disabled for one frame, then draws again).
- Scroll to Outcome: when the metric row is 35% visible, four numbers count up over 1200ms with ease-out-quart: −38%, 61%, 4.8, 212k. Suffixes render at 32px next to the 72px figure.
- Below: a coral-tint quote card, then the “Next case study” band. Hovering it moves the round arrow button 8px left and rotates it −45° over 360ms.
- The “Next project” link in the bar smooth-scrolls to the band.
Structure
1280 × 800 (56px side padding)
┌──────────────────────────────────────────────────────────────────────┐
│ Noor Halabi Case study 04/06 Work About Notes Next project │ 60 sticky
│▔▔▔▔▔ 2px coral progress │
├──────────────────────────────────────────┬───────────────────────────┤
│ • Kelda Ferries · iOS & Android · 2025 │ ┌───────────────────────┐ │
│ │ │ fjord gradient sun │ │
│ Ebb (250px italic Literata, teal) │ │ ┌─phone 236×480─┐ │ │ art card 500 tall, r22
│ │ │ │ ticket + QR │ │ │
│ Making the 07:40 to Holm feel like a │ │ │ Hold to board │ │ │
│ habit, not a hassle. (34px, 17ch) │ └─────┴───────────────┴─┘ │
├──────────┬──────────┬──────────┬─────────┴───────────────────────────┤ 1px ink rule
│ ROLE │ TIMELINE │ TEAM │ SHIPPED │ facts
└──────────┴──────────┴──────────┴─────────────────────────────────────┘
below the fold (each section is a 3fr / 9fr grid, 96px top padding):
01 Problem │ h3 44px + two paragraphs (62ch)
02 Process │ h3 + paragraph + 3 sketch figures (4:5 ruled pads)
03 Outcome │ h3 + 4-up metric row
quote card (coral tint, 56/64 padding) → next-project band (min 260px)
<header class="bar">with brand link, counter, nav links, and<span class="prog">.<main>→<section class="hero">(7fr/5fr grid): text column,.art(decorative,aria-labeldescribing the scene),<dl class="facts">spanning both columns.- Three
<section class="s">, each with<h2>(number in<b>+ label) and a content<div>. - Sketches are
<figure>with an inline SVG (aria-hidden) and a<figcaption>. <blockquote>with quote SVG,<p>and<footer>for attribution.<a class="next">as the closing band.
Tokens
:root {
/* colour: sage ground, deep teal, one coral accent */
--bg: #e8ede6; /* page */
--surface: #f5f6f1; /* phone screen */
--sea-1: #bcd3cc; /* fjord light */
--sea-2: #6f9c94; /* fjord mid */
--sea-3: #2f5a57; /* fjord deep, title, figures, buttons */
--ink: #1c2a24; /* text, rules */
--ink-2: #4c5d55; /* body copy (6.4:1) */
--ink-3: #7d8b84; /* labels */
--line: #c9d3cb; /* hairlines */
--accent: #d9674f; /* numbers, progress, highlights, focus */
--accent-soft: #f3d6cc; /* quote card */
--pad-paper: #f7f4ea; /* sketch pad */
--pad-rule: #e9e3d1; /* sketch pad ruling, 24px pitch */
--next-a: #4a3a26; --next-b: #8a6a3e; --next-glow: #e9b97a; --next-ink: #f6efe2;
/* type */
--serif: "Literata", Georgia, serif;
--sans: "Figtree", system-ui, sans-serif;
/* layout */
--pad: 56px;
--bar-h: 60px;
--r: 22px;
--r-sm: 12px;
--shadow: 0 24px 48px -24px rgba(28, 42, 36, .35);
/* motion */
--t-micro: 180ms;
--t-draw: 1400ms;
--t-count: 1200ms;
--t-arrow: 360ms;
--ease: cubic-bezier(.2, .7, .2, 1);
--ease-out: cubic-bezier(.16, 1, .3, 1);
}
Typography
| Role | Family | Size | Weight | Line-height | Tracking | Case |
|---|---|---|---|---|---|---|
| Title “Ebb” | Literata italic | 250px | 400 | .8 | −0.05em | Title |
| Lede | Literata | 34px | 400 | 1.18 | −0.015em | sentence |
| Section h3 | Literata | 44px | 400 | 1.12 | −0.02em | sentence |
| Section number | Literata | 64px | 400 | 1 | −0.03em | numerals |
| Metric figure | Literata | 72px (suffix 32px) | 400 | 1 | −0.04em | tabular |
| Quote | Literata | 36px | 400 | 1.25 | −0.015em | sentence |
| Next title | Literata | 64px | 400 | 1 | −0.03em | Title |
| Figcaption | Literata italic | 15px | 400 | 1.4 | 0 | sentence |
| Body | Figtree | 17px | 400 | 1.6 | 0 | sentence |
| Facts value | Figtree | 15px | 400 | 1.45 | 0 | sentence |
| Labels (dt, h2) | Figtree | 12–13px | 600 | 1.2 | +0.08em | UPPERCASE |
| Bar links | Figtree | 14px | 400 | 1 | 0 | Title |
Motion
| Element | Trigger | Property | From → To | Duration | Easing |
|---|---|---|---|---|---|
.prog | scroll | width | 0 → 100% | live | — |
| sketch strokes | sketch row 35% in view | stroke-dashoffset | --len → 0 | 1400ms | --ease |
| sketch replay | click sketch row | dashoffset reset, then draw | instant → 1400ms | — | --ease |
| metric figures | metric row 35% in view | text value | 0 → target | 1200ms | ease-out-quart 1-(1-t)^4 |
| next arrow | hover .next | translateX, rotate | 0,0 → −8px,−45° | 360ms | --ease-out |
| anchor jump | click “Next project” | scroll | smooth | browser | — |
Reduced motion: transitions become 1ms, count-up duration 1ms (numbers appear final), scroll-behavior:auto.
States
- Bar links:
--ink-2at rest,--inkon hover; “Next project” is always--ink600. - Focus-visible: 2px coral outline, 3px offset, 4px radius on every link and the sketch row.
- Sketches before reveal: strokes invisible (fully dashed out); pads and captions are visible so the row never looks empty.
- Metrics before reveal: show “0%”, “0.0”, “0k” in final typography so layout doesn’t shift.
- Next band hover: arrow disc shifts and rotates; band background unchanged.
Accessibility
- Facts use a
<dl>; each fact is a<div>with<dt>/<dd>. - Section labels are real
<h2>s; the big statement in each section is an<h3>. - Sketch SVGs are
aria-hidden; the caption carries the meaning. - The metric count-up changes text content; it is not a live region (it runs once and would be noisy). Final values are reached within 1.2s.
- Body copy
--ink-2on--bgis 6.4:1;--ink-3labels are 3.6:1 and only used at 12px+ uppercase 600 for non-essential labels. - The phone art is
aria-labelled as one image; its fake UI is not focusable.
Responsive rules
- ≥ 1280: as specified.
- 1024–1279: title 200px; art card 440px tall; section grid 2fr/10fr.
- 768–1023: hero stacks (text above, art card full width at 420px tall); facts 2×2; section labels stop being sticky and sit above content; sketches stay 3-up.
- < 640: title 140px; lede 26px; sketches 1-up; metrics 2×2 at 56px; quote 26px with the mark above the text; side padding 20px.
Acceptance checklist
- Title is italic Literata at 250px, colour
#2f5a57, line-height .8. - Hero, phone mockup and the full facts strip are visible within the first 800px.
- Facts strip has a 1px ink top rule and 1px
--linedividers between four columns. - Progress line on the bar tracks scroll from 0 to 100%.
- Section labels stick at
top:84pxbeside their section. - Sketches draw in over 1400ms when 35% visible, and clicking the row replays them.
- Metrics count up once over 1200ms to −38%, 61%, 4.8, 212k with 32px suffixes.
- The QR code has three finder squares and is built in SVG, not an image.
- Next band arrow moves −8px and rotates −45° on hover.
- Every link shows a coral focus ring.
- With reduced motion, everything is visible in its final state with no animation.
Implementation notes
Self-drawing sketches. Give each shape its own path length via a custom property so one rule handles every stroke; disable transitions for one frame to replay.
.sk svg * { stroke-dasharray: var(--len, 600); stroke-dashoffset: var(--len, 600);
transition: stroke-dashoffset 1400ms cubic-bezier(.2, .7, .2, 1); }
.sk.drawn svg * { stroke-dashoffset: 0; }
.sk.reset svg * { transition: none; }
sk.addEventListener('click', () => {
sk.classList.add('reset'); sk.classList.remove('drawn');
void sk.offsetWidth; sk.classList.remove('reset');
requestAnimationFrame(() => sk.classList.add('drawn'));
});
Count-up with stable layout. Render the final typography at zero first; animate text only.
function count(el) {
const to = +el.dataset.to, dec = +(el.dataset.dec || 0), t0 = performance.now();
(function f(t) {
const k = Math.min(1, (t - t0) / 1200), e = 1 - Math.pow(1 - k, 4);
el.innerHTML = (el.dataset.pre || '') + (to * e).toFixed(dec) + `<small>${el.dataset.suf || ''}</small>`;
if (k < 1) requestAnimationFrame(f);
})(t0);
}
A believable QR from a seeded grid. 25×25 modules, three 7×7 finder squares drawn as one even-odd path each, the rest from a deterministic PRNG so it looks the same every load.
let s = 7; const rnd = () => (s = (s * 16807) % 2147483647) / 2147483647;
// skip finder zones, add <rect width=1 height=1> where rnd() > .52
Common mistakes: putting the sticky label on the section instead of the <h2> (it needs align-self:start inside the grid), counting numbers with setInterval, and letting the phone mockup’s fake buttons receive focus.
Details
- Palette
- Type
- Literata · Figtree
- Motion
- Subtle motion
- Build
- One session
- Tags
Studied
Susan AcharyaDraw one scene and let it move a little. The words stay calm on top.
All sourcesOn the shelves