Skip to content

SECTION

Interest card

A kicker, a date, a name and a line about it. Drop it inside a hairline grid.

Three interests

MOVEMENT SINCE 2016
Capoeira

Keeps the ego in check, which is more than most code review manages.

SOUND SINCE 2011
Sampling

Chopping a loop is the same craft as building an editor β€” small decisions, judged by ear.

CO-WORKER SINCE 2019
Rico

Walk enforcer. Unimpressed by deadlines.

HTML
<div class="hairline-grid" style="--cell:240px; width:100%">
  <div class="hairline-cell interest-card">
    <div class="interest-card-head">
      <span class="interest-card-kicker">MOVEMENT</span>
      <span class="interest-card-note">SINCE 2016</span>
    </div>
    <span class="interest-card-title">Capoeira</span>
    <p class="interest-card-body">Keeps the ego in check, which is more than most code review manages.</p>
  </div>
  <div class="hairline-cell interest-card interest-card-muted">
    <div class="interest-card-head">
      <span class="interest-card-kicker">SOUND</span>
      <span class="interest-card-note">SINCE 2011</span>
    </div>
    <span class="interest-card-title">Sampling</span>
    <p class="interest-card-body">Chopping a loop is the same craft as building an editor β€” small decisions, judged by ear.</p>
  </div>
  <div class="hairline-cell interest-card">
    <div class="interest-card-head">
      <span class="interest-card-kicker">CO-WORKER</span>
      <span class="interest-card-note">SINCE 2019</span>
    </div>
    <span class="interest-card-title">Rico</span>
    <p class="interest-card-body">Walk enforcer. Unimpressed by deadlines.</p>
  </div>
</div>

Three tones, and a card you can click

Same card, doing a different job. Give the kicker a tone and it grows a small square: .interest-card-tone-lead for the one you want read first, -steady for the ordinary case, and -quiet for the one that is just always there. Quiet dims the label as well as the square β€” a bright label beside a dim mark reads as a mistake rather than as a third step.

The first card below is an <a>. Add .interest-card-link and the whole cell is the target β€” hover it, then tab to it. Everything inside stays text, because a button inside an anchor is invalid HTML and gives a keyboard reader two stops where the design has one.

The arrow is yours to write; the library ships no glyphs. Put one in the note and the card says it is a link before anybody hovers it β€” at rest a linked card is otherwise identical to the three beside it, and hover is not an affordance on a touchscreen.

A dated strip, with one entry leading

BUILDING 2026 Β· 04 β†—
A 2.5D modelling tool

Drawing, extruding, exporting. Most of the week goes here, and the whole cell opens it.

PLAYING WITH 2026 Β· 02
Go and a drawing library

Small visual experiments with no product attached to them.

READING 2025 Β· 11
Compiler books, slowly

Twenty pages a week. It is not a project and it does not need to become one.

Two paragraphs, because this one is a wrapper β€” the shape rendered Markdown arrives in.

HTML
<div class="hairline-grid" style="--cell:240px; width:100%">
  <a class="hairline-cell interest-card interest-card-link" href="#">
    <div class="interest-card-head">
      <span class="interest-card-kicker interest-card-tone-lead">BUILDING</span>
      <span class="interest-card-note">2026 Β· 04 β†—</span>
    </div>
    <span class="interest-card-title">A 2.5D modelling tool</span>
    <p class="interest-card-body">Drawing, extruding, exporting. Most of the week goes here, and the whole cell opens it.</p>
  </a>
  <div class="hairline-cell interest-card">
    <div class="interest-card-head">
      <span class="interest-card-kicker interest-card-tone-steady">PLAYING WITH</span>
      <span class="interest-card-note">2026 Β· 02</span>
    </div>
    <span class="interest-card-title">Go and a drawing library</span>
    <p class="interest-card-body">Small visual experiments with no product attached to them.</p>
  </div>
  <div class="hairline-cell interest-card">
    <div class="interest-card-head">
      <span class="interest-card-kicker interest-card-tone-quiet">READING</span>
      <span class="interest-card-note">2025 Β· 11</span>
    </div>
    <span class="interest-card-title">Compiler books, slowly</span>
    <div class="interest-card-body">
      <p>Twenty pages a week. It is not a project and it does not need to become one.</p>
      <p>Two paragraphs, because this one is a wrapper β€” the shape rendered Markdown arrives in.</p>
    </div>
  </div>
</div>

Reference

Read from sections/interest-card.css when this page was built, so it cannot fall behind the stylesheet.

CLASSES.interest-card.interest-card-head.interest-card-kicker.interest-card-note.interest-card-title.interest-card-body.interest-card-tone-lead.interest-card-tone-steady.interest-card-tone-quiet.interest-card-muted.interest-card-link
READS--ds-accent--ds-cream--ds-dot--ds-focus-ring-inset--ds-focus-width--ds-font-body--ds-font-display--ds-gap-inline--ds-gap-loose--ds-gap-tight--ds-ink--ds-ink-faint--ds-ink-soft--ds-motion-fast--ds-raised--ds-rule-strong--ds-sunk--ds-text-control--ds-text-h3--ds-text-label--ds-text-meta--ds-track-meta--ds-track-note--ds-track-snug--ds-weight-display

Notes

IN A ONE-PER-VIEW RAIL, THE BODY GOES

Put these in a rail and on a phone each card gets a whole screen and about two seconds. The kicker, the title and the date are what a reader uses in two seconds; the paragraph is not. So the body reads display: var(--rail-brief, flex) β€” the rail sets that property when it is showing one card at a time, and nothing else sets it, so a card anywhere else is untouched.

Worth knowing what that costs: the text is gone for everyone at that width, screen readers included. On a card that links somewhere it is a summary of a page the reader can open. On a card that does not, it is the only copy there was β€” so give those cards a title that stands on its own.

THREE NAMES, NOT A MARK PLUS TWO TINTS

One class that draws the square and two that recolour it is the tidier CSS, and it was the first thing written here. It also means .interest-card-tone-lead on its own draws nothing at all β€” no mark, no error, no clue. Three complete names cost a repeated selector list and buy a caller who cannot get it half right, and one frontmatter word maps straight onto one class with no branch in the middle.

THE BODY IS A PARAGRAPH AND A BOX OF PARAGRAPHS

Write <p class="interest-card-body"> for one sentence, or put the class on a wrapper and pour rendered Markdown into it. Both draw the same, and the second is the only shape a caller can produce from a two-paragraph entry β€” the fragment arrives as bare <p> nobody can put a class on.

It was a paragraph style alone at first, and that is a trap this system has already been caught in once. The wrapper set no display and no gap, the reset had already zeroed every p margin, and two paragraphs drew exactly 0px apart and read as one run-on block. Same fix as timeline-text, same gap as the card puts between its own children.

WHY THIS IS NOT A FEATURE CELL

They are siblings and they are separate on purpose. A feature cell leads with a picture and says what a thing is; this leads with a pair of labels and says what somebody does. The part they share is the cell, which they both get from the grid.

The head row is baseline-aligned, not centred. The kicker is 11px and the note is 10.5px; centring leaves the two strings visibly unaligned, which reads as a rendering fault. Same rule as the section head, same half-pixel reason. A toned kicker is a flex row and still lines up, because a flex container takes the baseline of its first item.

The right-hand label is .interest-card-note, and it used to be -since. It held "SINCE 2016" when it arrived and now holds "2026 Β· 04" as often as not β€” a class named after the string somebody put in it is a name that stops being true without anything failing. It is named for the slot instead, exactly as section-head-note is, which is the same job at the same end of the same kind of row.

A linked card takes an inset ring. It is a grid cell sitting against hairlines it shares with its neighbours, so an outset ring gets drawn half underneath the cell next door. Same reason menu-item and accordion-head are inset, and the transparent outline beside it is what survives Windows high-contrast mode, where a box-shadow is not painted at all.