Sightlines v2 · pattern sheet · 17 September 2026

What every page is made of.

A v2 page carries no style of its own. It composes a frame (two columns, the same two left edges on every page), the search module in one of two states, at most two strips of controls, the content, and where it applies a constant foot. Every clickable thing is one of five controls. Every piece of text is one of the type roles. The only bordered box is an island: an interactive thing that is not the page's content.

Everything on this sheet is live CSS from site.css (tokens, type roles) and v2/frame.css (the frame and controls). Change a token there and every page follows; that is the point. The last section shows Ask, Your Films and the Collection rebuilt from these parts.

1 · Tokens

The numbers a brand pass changes. Color and type live in site.css; the layout numbers live at the top of frame.css.

Color

--bg · page
--bg2 · fields
--card · islands
--line · rules, borders
--ink · text
--dim · secondary text
--amber · the one accent: primary, on-state
--amber-soft · kickers, text links

Type roles

t-displayThe page's one display line
t-titleA page or section title, serif
t-subtitleA subsection, sans semibold
t-cardA film title on a card
t-kickerA label over a group · always amber-soft
t-bodyRunning text: descriptions, doc sections, reception. One measure: 64 characters.
t-readLong reading: dossiers and essays, serif, 68 characters.
t-noteA secondary line: counts, provenance, hints, why-lines. Dim, never a panel.
t-metaYears, counts inside controls, the smallest print

Layout

tokenvaluegoverns
--rail270pxthe left column: title, then facets or the film page's rail
--gutter28pxthe column gap and the gap between stacked regions (18 until 2026-09-13; the pages read cramped)
--measure / --measure-read86ch / 80chthe only two text widths (64 / 68 read as unnecessarily narrow, 2026-09-13)
--s-1 … --s-74 · 8 · 12 · 16 · 24 · 32 · 44pxthe spacing scale: every margin, padding and gap in the v2 sheets is a step on it; hairlines under 4px stay literal (2026-09-17)
--gap-grid24pxthe one gap between cards, tiles and doors on a page grid
--ctl-h / --btn-h34px / 38pxpills, tabs, selects / buttons
--field-h / --field-h-lg38px / 44pxan in-page field / the site search field, one height on every page (hero and bar differ only by the intake row)
--radius / --radius-lg / --radius-pill8 / 10 / 999pxbuttons and fields / islands / pills

Spacing

--s-1 · 4
--s-2 · 8
--s-3 · 12
--s-4 · 16
--s-5 · 24 · the grid gap
--s-6 · 32
--s-7 · 44

Seven steps. A margin, a padding or a gap anywhere in frame.css or v2.css is one of these, so a rhythm change is one edit; tools/lint-css.py refuses a value off the scale, a literal color, a px font, an !important or an inline style.

2 · The frame

Two columns. The title always sits over the rail; the search module always over the main column; content and its foot in the main column; facets or the film rail in the rail. A page with no rail leaves the rail empty below the title. So there are two left edges on the site, and every page uses the same two.

headtitle · count · dek
toolsthe search module — hero (Browse · Ask · Your Films) or bar (everywhere else)
sidefacets with recounts, or the film rail; empty on Your Films and the empty Ask
main≤ 2 strips, then the content: a wall, a reading, the Read sections
footthe constant action row (collection, results) — sticky

The two states of the search module

Hero: the page is the search. The field is 46px, the intakes sit under it as quiet buttons, the hint is ghost copy in the field.

Bar: the page is something else (a collection, a result, a film). One line, 38px, no intake row.

The one page grid

.third

Two of six tracks. A build tile, a course card, the door tile.

.third

Three across on a wide window.

.third

A half under 1240px; the full row on a phone.

.door = .half

Three of six tracks. Your Films' doors; the reading's portrait cards, two across.

.half

The gap is --gap-grid, the same on every page.

.full

All six. A thread card, a map panel, a door with a picture beside its words.

Six tracks (.doors); a child takes .third, .half or .full, and a .door is a half by itself. Your Films, the reading page and a course row divide the same width — no page draws a grid of its own (2026-09-17).

3 · Controls

Five, and only five. If a new thing needs clicking, it is one of these.

Button — does something

Films around this →

Primary is the one thing the page most wants done; at most one per strip. An arrow only on a button that leaves the page. Quiet for secondary intakes.

Tool — an icon for a utility

Make a course from these →

The strip rule (2026-09-17): one or two text doors, then the tools as icons in one order — Share · Copy a post · Save as image · Print / PDF · Export to Letterboxd (a film page adds Add to your list first) — only the ones that apply, inside one .tool-row. 32px, the line icon, the label as a rollover on hover and focus; on a phone, with no hover, the label sits under the icon as a caption. Share always opens the social sheet (Facebook · X · WhatsApp · Reddit · Email · Copy link) with the page's card and a post line. A page's own conversion door (an answer's "Share this" preview) is not a tool and stays a text button in its island. So the row no longer dominates the page (Adrian, 2026-09-16: "it is not so much the number of buttons as their size").

Pill — narrows or toggles, shows a count

Tab — switches views of the same thing

Select — a pill that opens a list

Field — typing; two heights only

The × inside the field clears the field, nothing else. A second field (Say more about your search) has no ×: a new question replaces everything below it. As you type, the field drops a list (the live site's typeahead, in the frame's tokens): titles with their year and director, and up to three directors with a film count, in one face; a director row opens the wall around their films; arrow keys and Enter pick (2026-09-17).

Busy — the state of anything that takes time

Refining… Reading the posters…

Click a button: it stays where it is, keeps its width, shows the ring and says what it is doing (SLBusy.start(btn, "Reading your taste…")). Rings are 14 · 18 · 28 px from tokens, never em, so a small-font context on a phone cannot shrink them. Never a bare ring without words.

A long generation — a course, a reading, about fifteen seconds — gets the working island: the large ring, a kicker naming the thing being made, a note with the time that counts up, a cancel where one exists; when it lands, the ring settles and the primary button opens the result (SLBusy.working(host, {kicker, note, elapsed:true})done(text, {href,label})). Reduced motion: the ring stands still; the words carry the state.

Island — the only bordered box

No list? Choose your way to a reading — choose between films, two at a time, and a taste profile builds from your choices.

36 choices · reading ready

An island holds an interaction that is not the page's content: the choice-modal launcher, the refine strip on Ask, a results page's control center (.island--feel: the eleven tone sliders, open, above the wall — the Facets page's dials; under them Narrow by, the facets as tabs with counts; under that the group panel: every way of grouping as a pill, one line under the chosen one, and the relation-rings toggle with its legend), and the AI-arrival door (.island--door: one strip for a visitor an assistant sent, naming what they came for and what else the page holds). Text is never boxed. Lists are never boxed. The one other bordered box is the door (.doors / .door): a landing page's panel — a kicker in the visitor's words, a promise, four posters (or a picture of the thing itself, .door-shot, where the door opens a tool), and the action that keeps it; Your Films is a page of doors, three to a row, on the standard frame: the head and its dek in the rail, the search module as the hero.

Strips — at most two above the content

6 of 6 films

Strip one: what you are looking at (tabs) and the modes (pills). Strip two: the grid's count and its controls. Nothing else stacks above the posters.

The set line — a seeded wall's first line

150 closest to HeatShow

Under the title on a results wall (the live site's "50 closest to Con Air · showing 50" bar, 2026-09-16): the count (and "37 of 150" when narrowed), how wide to make the wall, Add all (it follows the narrowed set and what is already on the list), and the tools. An Ask answer has the line without the Show pills, since a wider answer would run the planner again. Past 25 films Save as image gives the full poster sheet.

Floating — Back to top

Back to top

On every page (components/totop.js): a quiet pill at the bottom center, absent until the page has scrolled a screen and a half, only on a page a few screens tall, gone again near the top. The Feedback button holds the left corner and the list pill the right; on a phone it sits above the list pill. Smooth scroll, instant under reduced motion.

4 · Names

A control says what happens, in the visitor's words. Nouns for views, verbs for actions, no code names.

todaybecomeswhy
titlesShow titlesa toggle names the state it produces
your 6 films · with their kinOnly these films · Add related films“kin” is our word, not theirs
Read 18Read 18the count is meta, not part of the name
SaveSave listsays what is saved
Copy linkSharethe site's share sheet (Facebook · X · WhatsApp · Reddit · Email · Copy link), as the live site — one method everywhere
Letterboxd CSV · PDF · ImageExport to Letterboxd · Print / PDF · Save as imageverbs
Read my taste → · Make a course →Read my taste · Make a coursearrows only where you leave the page
Screenshot or photo · List or CSVFrom a screenshot · From a CSVthe field already says what it takes
in your territoryIn my tasteplain
Widen the poolShow moreplain
Open as a list · Build a quick course from these →Save as a list · Make a course from theseverbs, no “quick”
reset · start overClear filters · Start oversays what is cleared

5 · Pages from the parts

The three pages you flagged, rebuilt with nothing but the frame and the controls above. Posters are placeholders. Browse, Results and the Film page use the same frame (Film: the rail carries facets, craft notes, sideways and kin; the main column the hero, tabs and reading).

Ask — empty

Atlas · Explore · Facets · Your Films · Ask · Essays · Courses

Ask for a film

Say how you want to feel, what the evening is, what you loved last.

Try one

Ask — answered

Atlas · Explore · Facets · Your Films · Ask · Essays · Courses

Films for “a quiet film about grief that ends with some hope”

82 films

Read as a restrained, intimate film about grief that leaves a quiet sense of hope — keeping the filter light so the feeling leads.

82 of 82 films

Your Films

Atlas · Explore · Facets · Your Films · Ask · Essays · Courses

Your films

Bring them any way you like. Sightlines keeps the ones it holds as a list you can organize, read about, share and export.

No list? Choose your way to a reading — choose between films, two at a time, and a taste profile builds from your choices.

36 choices · reading ready

Your lists on this device

Collection

Atlas · Explore · Facets · Your Films · Ask · Essays · Courses

Summer noir

6 films · from letterboxd.com/adrian/list/summer-noir · saved 7 Sep

6 of 6 films

6 · The rules (for v2/README.md)

  1. No page CSS. A page is markup that composes the frame and the controls. If a page needs something the frame lacks, the frame gains a named variant, it appears on this sheet, then the page uses it.
  2. Two left edges. Title and rail on the first; tools, content and foot on the second. Nothing is centered; nothing is indented by hand.
  3. Five controls. Button, pill, tab, select, field. One primary button per strip. Arrows only where you leave the page.
  4. At most two strips above the content; the tabs and the modes share the first.
  5. Type by role. Titles t-title; the page's one explanatory line t-note at the measure; running text t-body; reading t-read; labels t-kicker. Two measures. No size, weight or color set outside the roles.
  6. Boxes are islands. A bordered box holds an interaction that is not the content. Text, lists and posters are never boxed.
  7. Names are the visitor's. Verbs for actions, nouns for views, counts as meta, no code words.
  8. One color of link in text (--amber-soft); the accent (--amber) is for the primary button and the on-state only.
  9. Waiting has one look. A control that is working keeps its place and size, shows the ring and names the work; a long generation gets the working island with the time. Rings are token-sized in pixels. No page writes its own spinner or its own "Loading…".
  10. One way to clear, one way to dismiss. A text field's × sits inside the field at its right and clears only the field. A panel that follows the page's own input — the island under an answer, a grid's control center, the four — has no ×: typing a new question replaces it, and nobody should have to clear things elsewhere on the page. Only an unprompted island (the film page's next step, "do yours") carries a quiet ×, top right, meaning "not now". A modal's × is top right. Never an × that clears more than the thing it sits in.
  11. Information, instruction and the call to action live apart. And the call matches what the person is doing on that page: someone with a Top Four wants to know what the four say and what to watch next, not their ancestors. Two doors at most. A menu of every outcome is no call to action; people gloss over all of it (Adrian, 2026-09-16). People do not read the interface. A panel that invites action holds one fact and one button, nothing else ("131 films fit … Share the list on social platforms and ask what people think." · Share this). An instruction sits next to the element it instructs — "Tap + on two or three…" above the posters, not in a panel three blocks up. Links to other things (courses, threads) get their own panel with a title. If a panel needs many words, the UI is not clear; make the UI do more and say less.
  12. One card per kind of content. A film is always the poster card; a course is always the course card (its posters, its title, its note — or, where the note would be noise, how many of the films at hand it holds); a viewing thread is the same card with its own posters, name and line; an essay is always the essay card (the index's look: title, subtitle, excerpt, and one meta line where the context has one). A link to any of them is never a text link, a pill or a new box. The cards come from grid.js (courseCard · threadCard · essayCard); the server sends one shape for each (_sbx_course_ref · _sbx_thread_ref · _sbx_essay_ref).
  13. Every number is a token. Spacing from the scale (--s-1--s-7, --gap-grid), colors from the palette and the named washes, sizes from the type tokens. No literal color, no px font, no !important, no inline style — tools/lint-css.py fails a commit on any of them. A restyle is one edit to a token or a frame rule, and every page follows (Adrian, 2026-09-17).
  14. One grid. A row of cards, tiles or doors is the six-track .doors grid with .third, .half or .full children; no page writes a grid of its own. A section's width is the frame's column; nothing caps it by hand.
  15. One strip rule. One or two text doors, then the tools as icons in one order — Share · Copy a post · Save as image · Print / PDF · Export to Letterboxd — each with its label as the rollover (a caption on a phone); Share always reaches the socials, with the page's card and a post line.