Portfolio · card deep-dive · v4 · 2026-04-12

Sizing consistency,
deeper palette,
combined mobile shots

Refinement of v3 based on three pieces of feedback. (1) Visual types were drifting in size and padding — numeral felt huge, monogram felt cramped, icon sat somewhere in the middle. Fixed by a shared shell across centred types, so numeral / icon / monogram are now sibling sizes in the same frame. (2) Text marks were using royal-10 / violet-10, which lost the weight of the original gradient. Moved to royal-8 / violet-8 — the exact anchor shades from the gradient — so text marks keep that deeper, saturated presence without being the gradient. (3) Monogram was in Geist Mono which clashed with Fraunces numerals — unified on Fraunces so they read as sibling typographic marks.

Also in this pass: the screenshot auto-tint is deepened (opacity 0.55 → 0.9) so it locks fully to the card's register colour instead of bleeding source hues through. And the mobile-screenshot section gains a combined M5 + M6 exploration — my read is yes, use both, with rules for hierarchy.

§1 · visual types

Six visual types, one layout

Each pair shows a work card (royal) beside a writing card (violet). The strip is 160px tall, spanning full card width. Content below is identical across pairs so the only thing that varies is the imagery treatment. Same hover state across all six: background lift + border change to the card's register colour. No per-type one-offs.

Type 1 — Screenshot · auto-tinted via mix-blend-mode: color. Author drops in any screenshot, component forces it into palette.
SELECTED WORK · 02

The Weekly App

Meal-kit POC that turns Coles recipes into a consolidated trolley.

  • REACT
  • VITE
  • NETLIFY
Type 2 — Diagram · palette-locked strokes (royal-10 / violet-10). Mermaid + Excalidraw exports swap in at render time.
request killswitch vendor
SELECTED WORK · 01

Planner App

GTD planner with persistent SMS, four-layer spend protection, and a killswitch that works.

  • TYPESCRIPT
  • CLOUDFLARE
  • D1
CHOKE POINT
ESSAY · ARCHITECTURE

One module for every paid call

Convention-based spend discipline fails under pressure. Structural choke points don't.

  • architecture
  • reliability
Type 3 — Numeral · Fraunces display at 112px in the card's register colour. Changed from v2: solid colour, not gradient.
01
SELECTED WORK · 01

Planner App

When no screenshot or diagram fits the brief, the numeral carries the card on typography alone.

  • TYPESCRIPT
  • GTD
Type 4 — Gradient mark · the signature. Use sparingly (see §2).
SELECTED WORK · FEATURED

Design system retrofit

Tokens-first architecture applied across three projects. Gradient-mark carries the abstract weight.

  • TOKENS
  • REFACTOR
ESSAY · SIGNATURE

Royal Tonal in twelve steps

When the content IS the palette — gradient-mark is the only imagery that makes sense here.

  • colour
  • design
Open question on gradient-mark. Your feedback: when many cards show the gradient, visual identity weakens and the page becomes soup. Fix for text marks (numeral, monogram) is done — they use card colour now. But gradient-mark is the gradient. Proposed rule: gradient-mark is reserved for featured cards only and for posts where the gradient itself is the subject matter (see "Royal Tonal in twelve steps" above). This caps its appearance at roughly one per page and preserves it as a moment-of-emphasis mark, not a filler type. If you agree, gradient-mark drops out of the author's default-choice set and becomes a conscious reach.
Type 5 — Icon · lucide-react, 68px stroke in card register colour. Subtle radial tint backs the icon.
SELECTED WORK · 03

MOB analysis

Quarter-by-quarter breakdown of a two-year B2B sales cycle from raw Salesforce exports.

  • ANALYSIS
  • SQL
ESSAY · META

Writing as research

The posts that forced me to understand what I was actually claiming about the systems I was building.

  • craft
  • meta
Type 6 — Monogram · Geist Mono at 44px in card register colour. Lightest-weight option, works when nothing else fits.
PLN
SELECTED WORK · 01

Planner App

Short-code lockup — the fallback when diagram and screenshot both feel forced.

  • TYPOGRAPHY
R/W
NOTE · FRAGMENT

Read-write reciprocity

Monogram in violet only. Good for index pages where many cards need to feel like siblings.

  • notes
Consistency mechanics. Every type shares: (1) 160px strip height, (2) card-register palette — royal for work, violet for writing, gradient reserved for §2 edge cases, (3) identical border, radius, hover transition. Six visual languages, one system. The auto-tint on screenshots is the load-bearing trick — it means the author never has to negotiate with palette on arbitrary image input.
§2 · the gradient rule

Why text marks use card colour, not gradient

v2 rendered the numeral with background: var(--grad-rv); -webkit-background-clip: text. That looked great on a single card. It looked muddy on a 2×2 grid because every text mark became the same gradient, regardless of whether the card was work or writing. The register split collapsed into visual noise.

The rule now: text marks inherit the card's register colour. Work gets royal-10. Writing gets violet-10. Nothing in between. The gradient still exists — it lives on the gradient-mark type and on featured card borders (see v2 §4) — but it doesn't leak into every card that happens to use a numeral.

Before — numeral uses gradient fill (v2 behaviour). Work and writing numerals look identical from 2m away.
01
SELECTED WORK · 01

Planner App

Gradient fill. Pretty in isolation; works against register signal in context.

  • TYPESCRIPT
04
ESSAY · LESSONS

Four guardrails

Writing card — but the gradient is indistinguishable from the work card on the left.

  • postmortem
After — numeral uses register colour. Royal vs violet reads instantly, kicker and tags reinforce rather than compete.
01
SELECTED WORK · 01

Planner App

Royal-10 numeral — same colour family as the kicker and the arrow. The card reads as one thing.

  • TYPESCRIPT
04
ESSAY · LESSONS

Four guardrails

Violet-10 numeral. The writing register is now carried by three coordinated signals, not one gradient.

  • postmortem
§3 · mobile screenshots

When the "screenshot" is a phone

Layout A's strip is ~420px × 160px on a 2×2 landing grid (~2.6:1). A mobile screenshot is ~390 × 844 (~1:2.16). The strip is about six times wider than tall, relative to the phone. Cover-cropping shows ~18% of the screen; contain-sizing leaves a 72×156 phone floating in a sea of padding. Neither reads as intentional.

Six options below, each rendered as a real strip so you can judge them directly. Same fake phone markup in all of them — the only variable is how it's placed inside the frame.

Option M1 — Top slice. Phone positioned at the top of the strip, growing downward off-frame. Shows header + nav + first rows only.
SELECTED WORK · 01

Planner App

M1 — natural if the app bar is the most recognisable UI element.

  • TYPESCRIPT
  • CLOUDFLARE
ESSAY · BUILD

The app bar problem

Feels fine in isolation. Weakness: the phone looks cut off, not framed.

  • mobile
Option M2 — Contained device. Whole phone visible, centered, small. Radial glow frames it.
SELECTED WORK · 01

Planner App

M2 — the phone is honest about being a phone. Reads as "here is the product".

  • TYPESCRIPT
ESSAY · SHIPPING

Holding the phone

Weakness: the phone is small — UI detail reads as "something" but not "this specific thing".

  • mobile
Option M3 — Tilted, bleeds right. Phone rotated 10°, positioned right-of-centre, extending above and below the strip. Radial glow on left feels intentional.
SELECTED WORK · 01

Planner App

M3 — the tilt converts "cropped phone" into "composed phone". Most editorial.

  • TYPESCRIPT
  • MOBILE
ESSAY · FEATURE

Why tilt the phone

Weakness: applies one "art direction" gesture per card — starts to feel like a trick if every work card uses it.

  • design
Option M4 — Dual cascade. Two phones, counter-tilted, overlapping. Suggests a flow or a before/after.
SELECTED WORK · 01

Planner App

M4 — good for products with a two-screen story. Overkill for single-screen apps.

  • TYPESCRIPT
ESSAY · PATTERN

Before and after

Weakness: requires two screens that pair cleanly. The author has to do art direction, not just capture.

  • pattern
Option M5 — Meta split. Left half is a numeral or label; right half is a tilted contained phone. Hybrid of Type 3 (numeral) and mobile screenshot.
SELECTED WORK
01
SELECTED WORK · 01

Planner App

M5 — strongest editorial feel. Meta label anchors the card, phone supplies proof.

  • TYPESCRIPT
  • CLOUDFLARE
ESSAY
04
ESSAY · 04

Guardrails for mobile

Weakness: the numeral now duplicates the kicker number. Redundant if both are shown.

  • mobile
Option M6 — UI detail zoom. Not the phone — one UI fragment (button group, list, panel) rendered at the strip's aspect ratio. Reads as "here is the interesting bit".
SELECTED WORK · 01

Planner App

M6 — doesn't pretend to show the whole app. Shows the exact moment the card is about.

  • TYPESCRIPT
  • DETAIL
ESSAY · DETAIL

The shape of a list

Weakness: requires a crop decision per card. No automatic answer from "here's the screenshot".

  • craft
Option Author effort Honest to UI Grid rhythm Read
M1 · Top slice low partial clean Safe default. Reads as "cut off" when the app bar isn't load-bearing.
M2 · Contained none yes clean Honest but tiny. UI detail disappears at grid scale.
M3 · Tilted bleed medium partial clean Best balance. Composition signals "this is a product shot", phone reads as intentional.
M4 · Dual cascade high yes mixed Great for two-screen stories, heavy otherwise. Save for hero cards.
M5 · Meta split medium yes mixed Strong editorial feel, but duplicates kicker number if the meta shows the same digit.
M6 · Detail zoom high yes clean Highest craft ceiling, highest author cost — requires a crop decision per card.
Revised read (v4): M5 + M6 together, with hierarchy. In v3 I recommended M3 (tilted bleed) as default and M1 (top slice) as fallback. Looking at the six options again with the deeper palette locked, M5 (meta split) and M6 (UI detail zoom) are genuinely the strongest two. They do different jobs: M5 anchors a card by number — it's "this is piece N in a set" — and M6 pulls one UI moment into focus — it's "here is the specific thing this case study is about". Because they solve different jobs, mixing them creates hierarchy rather than noise. See below.
§3b · combined mobile treatments

M5 and M6 side by side

Your question: can we use both M5 and M6 for visual variety, or is that too busy? My view: yes, use both, but with rules. The risk isn't visual busy-ness — both compositions are clean. The risk is that both want to be the standout card, so putting them next to each other without intention flattens the hierarchy they're supposed to create.

Row 1 — M5 (meta split) + M6 (UI detail zoom). This is how a 2-card row would read with one of each type.
SELECTED WORK
01
SELECTED WORK · 01

Planner App

M5 anchors this card as the first piece in a sequence — the big 01 carries the ordering.

  • TYPESCRIPT
  • CLOUDFLARE
SELECTED WORK · 02

The Weekly App

M6 pulls a specific UI detail — the trolley list — into focus without pretending to show the whole app.

  • REACT
  • VITE
Row 2 — A full 2×2 grid with M5 used as the anchor card and M6 for the others. This is the rule I'd ship: one M5 per grid, M6 for the rest.
FEATURED
01
SELECTED WORK · 01

Planner App

Anchor card — M5 signals "start here" without needing a featured border.

  • TYPESCRIPT
  • GTD
SELECTED WORK · 02

The Weekly App

Secondary card — detail zoom points at the trolley consolidation feature.

  • REACT
  • VITE
SELECTED WORK · 03

MOB analysis

Secondary card — detail zoom points at the quarterly breakdown table.

  • ANALYSIS
  • SQL
SELECTED WORK · 04

Design system retrofit

Secondary card — detail zoom points at the token playground.

  • TOKENS
  • REFACTOR
The rule: "Max one M5 per grid, M6 for the rest." M5 is the anchor card — it says "start here, this is piece 01." M6 is the body vocabulary — every other work card uses it. Together they create a clear hierarchy: M5 reads as "this is the one the page wants you to look at first," M6 reads as "and here's the rest of the selected work." You get visual variety without competing signals.
When NOT to combine them. On /work and /writing index pages where every card is part of one flat list, skip M5 entirely and use M6 throughout. The point of M5 is that it anchors one card — if there's no obvious "first" card in the list, M5 has nothing to anchor and the numbers become noise. Restrict M5 to the landing grid (four cards, one featured) and the related-work footer inside case studies (where the current case study is the anchor by absence).

Recommendation (v4)

Lock Layout A (top third strip, content below) as the card spec. All six visual types render cleanly at sibling sizing in the shared centred-mark shell, and the content-below pattern is the most familiar scan order.

Adopt the deep text-mark colour rule: numerals and monograms use royal-8 for work and violet-8 for writing — the exact anchor shades of the original gradient. Text marks keep the weight the gradient gave them without collapsing register differentiation. Monogram moves to Fraunces so it reads as a sibling of the numeral.

Adopt the deep screenshot tint: mix-blend-mode: color at opacity: 0.9, background royal-8 / violet-8. Any source image is pulled fully into the card's register colour with no gradient bleed-through. Author effort stays at zero.

For mobile screenshots, combine M5 (meta split) + M6 (UI detail zoom) with a single hierarchy rule: "Max one M5 per grid, M6 for the rest." On /work and /writing index pages, use M6 only — M5 anchors the landing grid and related-work footer, nowhere else.

Open questions still to resolve: