Article

The reading experience. This is the most important pattern on the site. Every design decision serves one goal: let the reader forget they’re looking at a screen and simply read.

Composition

A standard article page assembles these elements in sequence:

  1. BreadcrumbAlex Priest -> Writing in the site header. Signifier for the nameplate, linking back to the homepage. The breadcrumb provides context without demanding attention. See Navigation.
  2. Article header<article><header> containing the h1 title (Signifier, 2rem, --text) and a .meta date line (Montreuil, 0.85rem, --text-2, tabular-nums). A --ui bottom border separates the header from the body. margin-bottom: var(--space-xl), padding-bottom: var(--space-lg).
  3. Prose container<div class="prose"> holds all body content. Signifier at 1rem, --text-2, text-wrap: pretty, hanging-punctuation: first last. Child elements are spaced with margin-top: var(--space-md). See Content components.
  4. Footnotes — On narrow screens, a .footnotes section renders at the bottom of the prose container. On wide screens (>=1080px), footnotes are lifted into the right margin as .margin-note-footnote elements and the .footnotes section hides via .footnotes.margin-active.
  5. Footer — The site footer acting as a colophon: navigation groups, copyright, theme toggle, accent picker, font size control. See Navigation.

Variants

Standard article

The default for writing posts. Full editorial treatment.

  • Drop caparticle.post.has-dropcap (added by client-side script when the first paragraph wraps to multiple lines). The first letter floats left at 3.5rem Signifier with weight 450 and a subtle ink-pooling text-shadow. --text color, not accent. Disabled on mobile and when the post opens with a blockquote.
  • Lede paragrapharticle .prose > p:first-of-type renders at 1.1rem in --text (primary color, not the --text-2 used for body prose). This newspaper convention draws the reader in. Resets to inherited styles if the post opens with a blockquote.
  • Letterpress headingsh3 elements receive a dual text-shadow creating the impression of type pressed into paper. Light mode: highlight above, shadow below. Dark mode: deeper shadow, subtler highlight.
  • Scroll progress bar — A 2px --accent bar fixed to the top of the viewport, width driven by animation-timeline: scroll(). Invisible at scroll top, full width at scroll bottom.
  • Side rail TOC — On wide screens (>=1080px), a table of contents appears in the left margin, positioned absolutely from the prose container and made sticky at top: 2.5rem. Montreuil, 0.75rem, --text-3 links. The active section is tracked via Intersection Observer and highlighted in --text at weight 500. Hidden on narrow screens and in print.
  • Margin notes — On wide screens, notes appear in the right margin at 0.75rem Montreuil in --text-2. Positioned absolutely, translated right of the content column. On mobile, block-level margin notes render as inline callout asides with decorative brackets. Inline and footnote-derived notes are hidden on mobile.

Now page

Class: article.now-page

  • No drop cap. First paragraph resets to inherited font-size, color, and line-height.
  • No lede styling. The first paragraph is body text, not an editorial opening.
  • Updated frequently, more casual in tone. The header includes location and last-updated date rather than a publication date.
  • Sections for currently reading, watching, and recent writing are appended below the prose content, each introduced by a .section-label-link.

Shortlist post

Class: article.shortlist-post

  • No drop cap. First letter resets all drop-cap properties (float: none, font-size: inherit, text-shadow: none).
  • No lede styling. First paragraph inherits standard prose styles.
  • Category pills<span class="shortlist-cat"> elements positioned in a hanging-indent layout. The paragraph containing a pill receives padding-left: 5.4em; the pill itself is absolutely positioned to the left at right: calc(100% - 7em). Montreuil, 0.65rem, uppercase, colored from the --pill-1/--pill-2/--pill-3 companion triple via client-side script.
  • Multiple short items rather than a single narrative. Each item is a paragraph with its category pill.

Link post

No special class on the <article> element. Distinguished by frontmatter: an external linkUrl field.

  • Title links out — The h1 wraps the title text in an anchor to the external URL. A small arrow glyph (&#8599;) follows the title as a separate link element (.link-arrow, 0.65em, --text-3). The title link uses the same weight-shift hover as post lists: font-variation-settings: 'wght' 400 to 'wght' 500.
  • “Must read” marginalia — On wide screens (>=1080px), link posts with mustRead: true display a .must-read-note annotation in the right margin. This includes a rough.js hand-drawn arrow SVG (.must-read-arrow, 80x20px) and a handwritten-style label in Caveat cursive (1rem, weight 600, --text-2). Hidden on narrow screens and in print.

Atmospheric context

These ambient layers apply to all article variants. They establish the materiality of the reading surface.

  • Scroll progress bar--accent color, 2px height, fixed to top of viewport. Width animated via animation-timeline: scroll() with a @keyframes scroll-fill from 0% to 100% width. z-index: 1000.
  • Side rail TOC — Left-positioned on screens >=1080px. Sticky at top: 2.5rem. Montreuil labels, --text-3 links that highlight to --text when active. Nested h3 links indent at padding-left: 0.75rem and render at 0.7rem.
  • Margin notes — Right margin on desktop (width 8rem, expanding to 10rem at >=1280px). Inline callouts on mobile with decorative SVG brackets.
  • Paper grain, vignette, crop marks — Documented in Atmosphere.

Code example

Full HTML structure of a standard article page (simplified from the Astro template):

<body>
  <div class="scroll-progress" aria-hidden="true"></div>

  <div class="site-wrapper">
    <header class="site-header">
      <nav class="breadcrumb" aria-label="Breadcrumb">
        <a href="/" class="name" style="view-transition-name: nameplate;">Alex Priest</a>
        <span class="separator" aria-hidden="true">-></span>
        <a href="/writing" class="current">Writing</a>
      </nav>
    </header>

    <main id="main">
      <article class="post has-dropcap">
        <header>
          <h1>Article title</h1>
          <p class="meta">January 15, 2026</p>
        </header>

        <nav class="toc" aria-label="Table of contents">
          <div class="toc-inner">
            <span class="toc-label">Contents</span>
            <ul class="toc-list">
              <li class="toc-item toc-h2">
                <a href="#section-one" class="toc-link is-active">Section one</a>
              </li>
              <li class="toc-item toc-h2">
                <a href="#section-two" class="toc-link">Section two</a>
                <ul class="toc-sublist">
                  <li class="toc-item toc-h3">
                    <a href="#subsection" class="toc-link">Subsection</a>
                  </li>
                </ul>
              </li>
            </ul>
          </div>
        </nav>

        <div class="prose">
          <p>The lede paragraph renders at 1.1rem in primary text color.
             The drop cap on the first letter floats left at 3.5rem.</p>

          <h2 id="section-one">Section one</h2>
          <p>Body prose at 1rem in --text-2.</p>

          <aside class="margin-note">
            <p>A margin note in the right gutter on desktop,
               an inline callout on mobile.</p>
          </aside>

          <h2 id="section-two">Section two</h2>
          <p>More body prose.</p>

          <h3 id="subsection">Subsection</h3>
          <p>Subsection content with letterpress text-shadow on the h3.</p>

          <section class="footnotes">
            <ol>
              <li id="fn-1"><p>Footnote text. <a href="#fnref-1">Back</a></p></li>
            </ol>
          </section>
        </div>
      </article>
    </main>

    <footer class="site-footer">
      <!-- Colophon: nav groups, copyright, settings -->
    </footer>
  </div>

  <aside class="side-rail" aria-label="Navigation">
    <!-- Book-spine nav links -->
  </aside>
</body>