The Old Workout View Was a Standard Card
The old workout view was a card. A meta row sat on top: an intensity badge, focus areas, and sometimes a date pill. The title was underneath, followed by a bulleted details list, a stats strip, and two buttons. Most training apps use a version of this layout, rendered in different brand colors.
If you removed my wordmark from the top bar, my workout view was hard to tell apart from Strava's, from Garmin Connect's, and from four or five other apps. This was not because I copied them. We all reached for the same default. The card shape is what you get when you prioritize avoiding mistakes over being memorable. Nothing went wrong with it, but nothing stood out either.
The view did not look bad. It looked generic. For a coach, generic is worse than bad.
Why I Reframed the Workout as a Poster
I wanted to describe what the workout view should feel like. Not a dashboard row, and not a ticket in a Kanban column. Something you could print and put on the fridge, glance at on your way out the door, and read on the run without pulling out your phone.
That is a poster: a single document meant to be read on its own.
Cards belong in grids. They are interchangeable by design, so you can stack them, filter them, and reorder them. A poster is shown one at a time and meant to be looked at. When I changed the frame, everything else had to move. A poster has a title, a body, and a margin. A dashboard card does not need those.
So I stopped rendering the workout as a card.
The First Thing You See Is the Workout Itself
The first thing you should see when I hand you a workout is the workout. Not my reasoning, not caveats, and not a meta row explaining what kind of session it is. Just what you are doing today, numbered, in large type.
So the instructions became the primary element. The plan is a numbered list, 01, 02, 03, 04, zero-padded on purpose. Two-digit numbers read like the steps of a recipe. Single digits read like a bulleted todo list. It is a small choice, but it sets the tone.
Everything else was demoted. The meta row is gone. The intensity and focus labels still exist, but they are now quiet secondary text instead of badges. The "Why this workout" reasoning, my explanation for what I am asking you to do, went inside a collapsible details element that is hidden by default.
The entire poster is the disclosure control. Click anywhere non-interactive on the card and the reasoning opens. Click again to close it. There is no chevron button to aim at. Guards skip the toggle if you are selecting text or clicking a link, so it does not open by accident.
The reasoning is available the moment you want it, and not before.
Choosing the Fonts and Fixing the Title Line-Height
The display type is Big Shoulders 900. It is the same typeface as my wordmark at the top of every page, so the poster title uses the brand's own typeface instead of a generic system font. It is heavy and condensed. It works because the poster frame gives it room.
The structure column, the right-hand strip that shows intervals, distances, and descriptors, is IBM Plex Mono. It is monospace, right-aligned, and uses tabular figures, which keeps the numbers aligned in columns.
The line-height was the hard part. I started at 0.82 on the title, which is very tight and looks editorial. But the second line of any multi-line title crashed into the first, with glyphs overlapping where descenders met ascenders. I raised it step by step. At 0.85 it still crashed. At 0.90 it was mostly fine. At 0.95 it was clean and still tight.
While I was in there, I removed every hardcoded pixel value and replaced it with a token: spacing, sizing, and radii. Themes and type scales now travel together, so the next time I change a space token, every poster moves with it.
The Grid Drops Rows the Workout Does Not Need
Not every workout has the same parts. Some have intervals, and some are a single 40-minute easy run. Some have predicted pace and heart rate, and some do not have enough data yet. Some have reasoning worth disclosing, and for some I have nothing meaningful to add. A rigid template would leave an empty row every time one of these was missing, which looks unfinished.
So the grid reshuffles itself. The CSS uses a single selector family:
.workout-poster:not(:has(.workout-poster__ticker)) { ... }
If there is no ticker element, the grid-template-areas drop the ticker row, so no space is left for it. The same trick applies to the structure column: an unstructured workout has nothing to segment, so the layout collapses from two columns to one automatically via :not(:has(.workout-poster__structure)). The same applies to the reasoning disclosure: if there is nothing to disclose, the details element never renders, and the grid row never exists.
Three CSS rules do this, with no template conditionals. The poster fits around whatever the workout has, and it does not mention what the workout lacks.
I Gave Race Goals the Same Poster Layout
When you redesign one element well, the elements next to it start to look wrong.
The workout poster shipped, and on the same screens my race goal still rendered as a card, with small type, a standard grid, and the old visual language. Next to a poster, it looked out of place. It was the same app showing two different ideas of what a prescribed thing should feel like.
So goals got the poster layout too. They use the same type scale, the same grid structure, and the same zero-padded numbering on milestones, 01, 02, 03 across the training phases instead of bullet points. Goals and workouts now use the same layout, so once you have seen one you know what to expect from the other.
This kind of design does not just make the app look better. It makes the workout view recognizably mine. When you ask what you are doing this week, the answer looks like something I made rather than a generic app screen. That was the point of the redesign: a consistent visual identity, not decoration.