# Timeline rail

> Six dated milestones hung on one continuous currentColor hairline: the year in a narrow column set against the rule, the event title and one short paragraph on the other side of it. The rail runs on above the first year and below the last entry, so the section reads as a length of a longer history rather than a closed list. It is a history and not a process: nothing is numbered and nothing asks the reader to do anything. States no colour and no font of its own.

Canonical: https://patternpaste.com/pattern/timeline-rail.html
Section: Timeline
Access: Free, and free to keep.
Needs: Requires a block theme on WordPress 7.0 to 7.1. Classic themes and page builders are outside our supported setup. Adaptive patterns use the block theme’s colour, spacing and typography presets; styled variations declare their own colours or type.
Blocks: column, columns, group, heading, paragraph
Keywords: timeline, history, milestones, years, about, rail, chronology

## Variations (2)

### Open rail (the default)

Identical markup in every theme.

The year hangs left against the rule, the event sits right of it, and the hairline is currentColor so it follows your text colour and cannot resolve to nothing. The columns are held side by side at every width, so the rail is unbroken on a phone as well.

### Mirrored rail

Identical markup in every theme.

The composition changes rather than the colour: the whole spread turns over. The rail runs down the right of the entries with the years hanging outside it, and the heading, the lede and every entry set to the right edge, so the section can sit against a left-hand column of a page.


---

## The signature moment: the rail runs past both ends

**The signature is that the hairline starts above the first year and carries on
below the last entry.** The first entry's copy group takes a spacing-70 top
padding and the last one takes a spacing-70 bottom padding, so the rule exists
for a stretch where there is nothing beside it at either end. A history that
begins exactly at its first entry and stops exactly at its last one reads as a
closed list of six things. This one reads as a length cut out of something
longer, which is what a company history actually is, and the last entry says so
in as many words.

The rail is a structural mark carrying the whole composition, so it is
`currentColor` and never an accent: it cannot resolve to nothing, it follows your
text colour, and it inverts with the section if you recolour it.

### How the rail is built, and why it is unbroken

There is no separator block and no rail element. Each entry is a two-column row
whose right column holds a group with a `border-left`, and consecutive entries
carry no gap between them, so those borders touch and form one line. The entries'
own top and bottom padding is what spaces the content, not the gap between rows.
That is why the rule is continuous rather than a stack of six dashes, and it is
also why adding an entry cannot break it.

**The columns do not stack.** `isStackedOnMobile: false` keeps the year beside
its entry at 390, which is the measured way to beat core's
`flex-basis: 100% !important` rule. If the row stacked, the year would drop above
the copy and the rail would break into six pieces at exactly the width where a
timeline most wants to be one line. The year column is 16%, which is about 56px
at 390 and holds a four-digit year at the `clamp()` floor with room to spare.

## Why it is a history and not a process

`steps-ledger` and `steps-run` are processes: numbered, ordered, and the reader
is inside them, deciding whether to start. Nothing here is numbered, nothing is
counted, and there is no next step. The years are real dates rather than
positions in a sequence, which is why they are set in a plain paragraph and not
in a `core/list`: an ordered list would renumber itself and would refuse a date.

It is also not `timeline-decades`, the other pattern in this section. That one
holds twenty single lines grouped under decade heads and has no rail at all. This
one is six open entries, each with room for a sentence, on a rule. Six moments
against thirty years is the difference, and it is a density difference rather
than a styling one.

## What it inherits from your theme

- **The typeface.** No font family is stated anywhere.
- **Your colours.** `base` for the ground, `contrast` for the type, both ending
  on a colour WordPress guarantees. The rail is `currentColor`.
- **Your spacing scale.** Every gap in the section, including the run-past at the
  two ends of the rail, is a spacing preset, so a theme with a generous scale
  gets a longer overhang.

## What it decides for itself

- **Full bleed with a 1240px measure.**
- **The 16/84 split** and the right-aligned year, so the years sit snug against
  the rule and form a hard edge down the section.
- **The reading measure.** Each entry's paragraph sits in a nested constrained
  group at 34rem, so the copy runs at about 65 characters instead of the full
  column.
- **The alignment of the year to its entry.** The year's `margin-top` is the same
  spacing preset as its entry group's `padding-top`, so the two tops line up in
  any theme, including the first entry where both are the larger run-past value.

## What to change first

1. **The six entries.** Duplicate a row to add one. The only thing to remember is
   that the first row carries the larger top padding and the last row the larger
   bottom padding: those two values are the run-past, and they belong to whichever
   rows are first and last.
2. **The years.** Plain text, so `2009`, `Spring 2009` or `Q1` all set. Anything
   much longer than four characters wants a wider first column.
3. **The entry copy.** One sentence that says what changed. Two sentences still
   fit; three turn the rail into a document.
4. **The heading and lede.** Written to say the rail is open at both ends. If you
   close the rail by removing the run-past, change that sentence too.
5. **The side.** Ship the base for a normal page, and `rail-mirror` where the
   section sits against something on the left of the page.

## Notes

- Core blocks only. No plugin, no script, no separator.
- Every colour is a fallback chain ending on a guaranteed colour, and every rule
  is `currentColor`.
- The rail is a border on a group inside a column, not on the column itself, so
  it does not depend on `core/column` border support.
