Paper first
Warm ground, soft edges, one pool of light from above. Surfaces are dressed as sheets of paper, not as rectangles on a dashboard.
Design language
Bookcrumbs is one card of warm paper, one quote, and a great deal of restraint. This is everything that holds it together — the ramp, the two faces, the three curves, and every element with the state it wears when you reach for it. All of it below is the real stylesheet, running live. Nothing here is a picture of it.
The product is a single screen with one job: hand over a thought from a book and then get out of the way. Everything below follows from that. Ornament is allowed, but it is never in front of the quote, and it is never the same twice in a row.
Warm ground, soft edges, one pool of light from above. Surfaces are dressed as sheets of paper, not as rectangles on a dashboard.
No rails, no sidebars, no counters competing for the eye. The note is the only thing that moves unless you ask it to.
Every accent is a diluted brown. Shine is a soft pass of light, never a saturated hue, and never more than a hairline wide.
An open book with a ruled page on each side. The topmost leaf turns over on hover, and closes on itself — its face and its back are the same shape, so the turn lands back on the open book it started from.
Ten steps of espresso, from the paper the card is printed on to the ink it is printed in. Every other colour in the house is one of these steps at some opacity. Click any swatch to copy its token.
The ramp is the material. These are the jobs it does.
Hairlines are ink at low alpha rather than their own colour, so a rule drawn on paper and the same rule drawn on ink belong to the same scale.
Each rule is shown twice: once on paper, once on espresso-900. The ink scale is cut for paper — reversed, it very nearly vanishes, which is why nothing in the house ever draws a rule on the dark ground. That ground is given a paper line instead.
Four raw channel triples carry every translucent surface, so a border and the text inside it are literally the same brown.
The ramp runs both ways: espresso-100 through 400 keep their contrast when the ground is the darkest step. This is how the app's own surfaces hold up.
Aa
Reading on ink
For inverted moments — the toast, the sealed crest, the reversed mark — the paper steps become the type and the ink step becomes the ground.
expresso-900 ground expresso-100 type expresso-300 detailFraunces reads the quotes. Hanken Grotesk runs the interface. They are never swapped: display for what was written, sans for what the product says.
Display
Aa
Fraunces
Self-hosted variable, weights 100–900, optical sizing on. Softness 80, wonk off. The quote, the counts, the roadmap titles.
--font-display: 'Fraunces', Georgia, serif
Interface
Aa
Hanken Grotesk
400 / 500 / 600 / 700. Everything with a job to do: buttons, bylines, tabs, labels, tooltips.
--font-body: 'Hanken Grotesk', 'Segoe UI', sans-serif
.note-text
We read to know we are not alone.
.spec-title
A note is a small thing
.about-intro h3
Good books. Lasting thoughts.
.project-item p
Let a little quiet into the day.
.royal-heading-label
The Royal Record
.changelog-dateline
3 days ago · New
.footer-attribution-label
Curated by
.project-tab
What's new
.book-link
The Royal Diaries of Krishnakumar
.author-line
by R. K. Narayan
.swipe-hint
Swipe to keep reading
Fraunces carries four axes. The house sets SOFT 80,
WONK 0 and lets opsz follow the size it is rendered
at. Move them and the setting below is the real declaration.
Handgloves
font-weight: 350;
One measure for the whole product: --note-content-max-width. The
card, the topbar, the panel and the footer are all that wide, so the page has a
single column of gravity.
760px is wide enough for a sentence and narrow enough that the eye returns to the left edge without hunting for it.
Space is a quarter-rem ladder and almost nothing else. Corners are pills, panels and sheets. Light comes from above in every case, always warm, never grey.
--radius-pillcontrols, chips, toast24pxthe note card18pxthe about panel14pxmedallions, tab rail12pxroadmap plates, icons7pxrule lozenges, rotated 45°50%crest, streak, node--radius-tabbare tabsPaper
An opaque sheet with a gilt gradient border, a highlight along its top inner edge, and a long soft shadow beneath. This is the card, the panel and this page's own sections.
expresso-50 + gradient borderGlass
Controls that sit over the card: white at 36%, a 12px backdrop blur, and the shadow that keeps them from floating away. They tint what is behind them.
surface-control + blur(12px)Gilt
Light travelling along a rule or over a pill. It is a 1px gradient moved by a background-position keyframe — never a border colour, never a glow filter.
--expresso-500 through transparentrest
a border and nothing else
--shadow-control
0 8px 22px rgba(0,0,0,.04)
--shadow-panel
0 12px 30px ink at 12%
the card
four layers, incl. an espresso glow
Three curves and three durations, and nothing else. Entering is a long settle, leaving is almost gone, and anything you can push, push back on. The curves below are drawn from the tokens themselves.
:hover transform would jump it the moment the pointer drifted off.--motion-enter and --motion-exit off the root, so the animation and the token can never disagree.The contrast figures below are measured from the tokens in this stylesheet as you load the page, not written down. If a ramp step moves, the audit moves with it.
Two pixels of ink at a four pixel offset. It is the same ring on every control, and it is never removed — only restyled for the surface it sits on.
aria-busy while one is on its way out.Hover and focus are shown as previews here, because a static page cannot hand you a pointer. Tab into any tile and you will get the real thing.
Glass by default, gilt at the top of the page, a sheet of paper once they sit
inside the card's meta. 36px square, 16px glyph, radius --radius-pill.
Rest
.about-button
Hover
translateY(-1px)
Active
scale(.94)
Disabled
opacity .56
Open
aria-expanded
The one warm call to action in the house. Paper until you reach for it, then the gilt comes up under it, a sheen crosses it, and the heart starts beating.
Hover
gilt rises, star in
Streak
.streak-badge
hover for the tooltip
Scroll or use arrow keys
Hint
.swipe-hint
nudges on a 2.2s cycle
Field
pill, surface-control
Ink ground, paper type, a pill, and an undo where there is something to undo. It stays mounted and fades, so opening and closing both ease.
A sheet of paper with two more behind it, four stars in the corners, a quote, a hairline with a lozenge at its centre, and two small controls. This is the live component, rendered by the same stylesheet as the site.
Five states, one component. Each tile wears the class the reader’s own card would be wearing at that moment — the ones the app actually toggles. The gesture hint rides along with the card in every one of these states; it is drawn once on the resting card rather than repeated down the column.
.note-shell
The reading card as it settles: a quote, a byline, two controls.
.note-content.is-expanded
A note too long for the fixed height outgrows the sheet instead of shrinking its type. On a phone the hint swaps its wording at the same moment, to name the gesture that folds it back.
.is-swiping
The card follows the pointer. will-change is on, and nothing about the paper changes.
.is-transitioning
Between two notes. The class only buys a compositing hint — the travel is animated from the motion tokens.
.note-shell.is-support
The one card that is not a quote: centred, with no actions, steam rising off the cup and a star at every corner. It arrives after fifteen to twenty notes and never twice in a row.
Three views on one panel, a rail of tabs, and a chronicle down a gilt spine. It is live: switch views, and the height holds so nothing jumps.
Laid out here rather than dropped from its toggle, so the whole panel can be read at once. On the site it mounts closed, drops twelve pixels below the button it belongs to, and raises a fixed veil over the page behind it.
Entries hang off a gilt spine with a lit bead at each one, and the freshest is
sealed in gold. These are the real entries, read from the same
/api/project-updates the menu reads — nothing here is
written by hand.
Two chapters, a gilt rule between them. Shipped work is dimmed and sealed; planned work grows a star when you reach for it. Each entry is a single line of Fraunces — the entries carry a title and nothing else, so the list stays a list.
The foot of every page: a gilt rule lit at its centre and a beating heart on it. The sign-off carries the current mark, cut in Roman numerals and bumped with every release.
Every custom property the page is actually running, read out of the cascade. This
is the contract: change a value in variables.css and this table, the
audit above, and every component on this page move together.
That is the whole system: one ramp, two faces, three materials, three curves, and a card that knows how to get out of the way.