Files
spine/docs/specs/2026-06-20-pico-css-styling-design.md

5.5 KiB

Spine — Pico CSS styling

Styles the index page using Pico CSS v2 via CDN, restructuring HTML to use Pico-native semantic elements and adding a small custom <style> block for the few things Pico doesn't cover.

CSS strategy

  • Pico CSS v2 loaded from CDN: https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css
  • No build step. No local CSS file. No Sass/PostCSS.
  • Light/dark theme auto-switches via prefers-color-scheme (Pico default).
  • Custom styles in a single inline <style> block inside <head>.
  • No Tabler Icons. Format glyphs use emoji instead.

HTML restructure

Pico styles semantic elements. The current <div>-heavy output is rewritten to use Pico-native elements. Only spine- prefixed classes remain for layout pieces Pico doesn't provide.

Current element New element Purpose
<div class="frame"> <article> Card container (Pico styles borders/padding)
<div class="titlebar"> <header> inside <article> Title bar with book count
<div class="group">WANT (3)</div> <hgroup><h2>WANT</h2><small>3</small></hgroup> Group header with count
<div class="row"> <div class="spine-row"> Book row (flex, Pico has no horizontal list)
<div class="detail"> <blockquote class="spine-detail"> Expanded notes section
<span class="pill want"> <mark class="want">want</mark> Status badge (colored per status)
<span class="glyph"> <span class="spine-glyph"> Format emoji
<span class="title"> <span class="spine-title"> Book title + author
<span class="muted"> <small> Author name (Pico styles <small> as muted)
<span class="tags"> <small> with tag text Category tags
<span class="trail"> <span class="spine-trail"> Recommendation trail

Custom CSS

In an inline <style> block in <head>:

.spine-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--pico-muted-border-color);
}
.spine-row:last-child { border-bottom: none; }
.spine-selected { background: var(--pico-secondary-background); }
.spine-glyph { width: 1.5rem; text-align: center; flex-shrink: 0; }
.spine-title { flex: 1; min-width: 0; }
.spine-trail { font-size: 0.85em; color: var(--pico-muted-color); }
.spine-detail {
  margin: 0 0 0 2rem;
  border-left: 2px solid var(--pico-primary);
}
.spine-detail p { margin-bottom: 0.3rem; }
.spine-detail footer { margin-top: 0.5rem; }

/* Status pill colors */
mark.want      { background: var(--pico-mark-background); color: var(--pico-mark-color); }
mark.reading   { background: #faeeda; color: #854f0b; }
mark.read      { background: #e1f5ee; color: #085041; }
mark.abandoned { background: var(--pico-muted-color); color: var(--pico-background-color); }

/* Pico-specific overrides */
article { margin-bottom: 0; }
article header { padding-bottom: 0.5rem; margin-bottom: 0.5rem; }

Format glyphs

Emoji per format, empty string if unset:

Format Glyph
hardcover 📖
ebook 📱
audiobook 🎧
nil / unset (empty)

Full page shell

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Spine</title>
  <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
  <style>custom styles</style>
</head>
<body>
  <main class="container">
    <article>
      <header>
        <strong>spine</strong>
        <small>N books · M reading</small>
      </header>
      …groups and rows…
    </article>
  </main>
</body>
</html>

Example output (Use of Weapons, expanded)

<hgroup><h2>READING</h2><small>1</small></hgroup>

<div class="spine-row spine-selected">
  <span class="spine-glyph">🎧</span>
  <span class="spine-title">Use of Weapons <small>Iain M. Banks</small></span>
  <small>:scifi: :literary:</small>
  <span class="spine-trail">Priya: If you liked Player of Games, this one will wreck you</span>
  <mark class="reading">reading</mark>

  <blockquote class="spine-detail">
    <p><small>[2026-03-02]</small> The two-track structure is doing something I can't name yet.</p>
    <p><small>[2026-03-07]</small> Zakalwe's competence reads as a wound.</p>
    <p><small>[2026-03-09]</small> The chapter numbering. Oh.</p>
    <footer>Format: audiobook · ISBN: 978-0316029193 · Added: [2026-02-20]</footer>
  </blockquote>
</div>

Empty state

<article>
  <header><strong>spine</strong></header>
  <p>No books yet.</p>
</article>

Files changed

  • spine.elspine-render-index and spine-render-empty-state rewritten to emit Pico-structured HTML with inline CSS

No new files. No new dependencies beyond the CDN <link>.

Out of scope

  • JavaScript interactivity
  • Cover image display
  • Write endpoints
  • Per-note format
  • ?id= selection without page reload (full page reload only)

Acceptance

  • Page renders with Pico CSS applied (fonts, spacing, colors match Pico defaults)
  • Light/dark mode switches with OS preference
  • Groups appear in order: WANT, READING, READ — zero-book groups omitted
  • ?id=... expands the matching book's detail with reading notes
  • Status pills have distinct colors per state
  • Format shown as emoji glyph
  • Recommendation trail shown when REC_BY present
  • Empty state shows "No books yet."
  • No console 404s (Pico CDN resolves)
  • No Tabler Icons reference in output