The same card parts, rearranged to give width back to the words, so a card can sit beside a
screengrab on the Screens lens at one width everywhere. Every frame draws the same five invented quotes with
the markup QuoteCard.tsx renders. Measurements are taken live in this browser.
Artefact — real classes, real pixelsCommentary — not the product
1 · Measure: every variant at 270, 320 and 380px
Variant
270px
320px
380px
overhead (card − measure)
card width for the list measure
measure
Δ
w/line
height
measure
Δ
w/line
height
measure
Δ
w/line
height
Measure is the width of the column the long quote's words flow in. Words per line averages every full line of all five quotes (last lines excluded). Height is the five cards' total, without gaps.
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
The hanging timecode column lets the eye run down the timecodes of a list; the words start at one edge.
Measured overhead 153px of every card width: the 1px keyline, 16px left padding, the timecode column (~56px plus an 8px gap) and the right reserve for the eye and star (4.5rem, 72px — .quote-group .quote-card). At 270px the words get 117px, under half the card. At 270px a long name runs past the card's right edge (blockquote .speaker is nowrap) — Control S too.
Control S
Screens already trims: 12px timecode, 13px words, right reserve 2rem.
The words drop to 13px (label size), which is chrome size, not the participant's voice. Overhead is still 103px because the timecode column and a 2rem right reserve remain.
A
The whole width minus 8px + 16px goes to the words. Same parts, same order of meaning (when, then what was said, who, tags). Pure CSS on the shipped DOM.
One extra row per card for the top line: about 21px (five cards at 380px: 704px against D2's 598px). The timecodes no longer form a column you can scan in a list. 8px of gutter against the left keyline.
B
Isolates the gutter: everything A gives except 8px.
8px narrower than A; same extra row.
C
A's measure, and the participant badge leaves the end of the quote, so the last line of words often ends sooner — about the same height as A. Reads like a message header: when, who, then what.
A long name is truncated with an ellipsis (the code never is). Attribution moves from after the words to before them — a change in how a quote reads, not only where. Needs four small rules beyond the move.
D1
No extra row: five cards at 380px are 620px against A's 704px. Every line after the first gets A's full width.
The first line loses the timecode and the toggle space, so a short quote gains little. The timecode sits in the words' line at a different size and face; a run-in reads busier than a header.
D2
No extra row, and the first line is full width too: the most words per card height. The timecode joins a row that already exists for "+".
The only variant that changes the DOM. The star (a state mark, not only a control) moves to the bottom right, far from where the eye starts on a long quote. The timecode is read last.
Keyboard and accessibility, per variant
Reading order (DOM)
Focus order vs what you see
Hit targets
Control
timecode · words · participant · tags · + · eye · star
Tab reaches the eye and star last, but they are drawn first-line right. Existing mismatch.
Measured in the states frames: about 18×18 (star) and 19×19 (eye), centres about 22px apart — under the 24px of WCAG 2.5.8 in size and in spacing. Unchanged by A, B, C, D1.
A, B
unchanged
Same mismatch, now more visible: the eye and star share the timecode's row, and Tab goes timecode → participant → tags → + → back up to the eye. Fix in the DOM: render the hide and star toggles straight after the timecode.
Same buttons. The top row has room to move the eye left by 2px (right: 2.15rem) and clear 24px spacing — free in A/B/C, impossible in the control where the words sit under them.
C
unchanged
Visual order is timecode, participant, eye, star, words, tags; DOM order is timecode, words, participant, tags, eye, star. The largest mismatch of all: worth a DOM change if C wins.
As A.
D1
unchanged
As the control: the toggles are drawn at the end of line 1 and reached last.
As the control.
D2
words · participant · timecode · tags · + · eye · star
Matches: the toggles come after the tags in both.
In flow, so spacing follows .badges's gap (0.35rem): centres measured 24px apart; the size is unchanged.
Screen readers hear the same content in every variant except D2, where the timecode comes after the words. The blockquote has no accessible name of its own, so the order of its children is the order a reader hears.
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
“I scrolled right past the delivery options the first time because they looked like an advert, and by the time I found the cheaper one I'd already typed my card number in, so I just went with the fast one and paid extra.”p4Ines
Implementing the winner in QuoteCard.tsx and the theme
Written for A (the owner's first idea, CSS only), with what changes for C or D2. Nothing here is implemented.
organisms/blockquote.css — blockquote .quote-row (display: flex; gap: 0.5rem; align-items: baseline) becomes a column: flex-direction: column; align-items: flex-start; gap: var(--bn-space-xs), and blockquote .quote-body gains align-self: stretch. The comment "Hanging-indent layout: timecode in left gutter" goes. .quote-group .quote-card { padding-right: 4.5rem } goes (the base blockquote.quote-card padding var(--bn-space-md) 1rem becomes … 1rem … 0.5rem on the left for A, unchanged for B).
atoms/toggle.css — .star-btn and .hide-btn keep top: 0.65rem; they already sit on what becomes the top row. Optional: .hide-btn { right: 2.15rem } to clear 24px spacing.
molecules/editable-text.css — .undo-btn { right: 3.35rem } and atoms/button.css.edit-pencil { right: 3.35rem } sit on the same top row; they still fit at 270px (the timecode is ~4rem). No change needed.
QuoteCard.tsx — for A, none required. To fix the focus order, render the hide Toggle, the undo button and the star Toggle straight after the timecode element instead of after .quote-row; the positions don't change because they are absolute. The parked moderator-question row (.moderator-question-row) keeps an invisible timecode as a hanging spacer — with the gutter gone that spacer should go too, or that row stays indented. The parked ExpandableTimecode wraps the timecode and inherits the top-row position.
frontend/src/islands/screens/screens.css (the other session's file — listed, not touched) — .screens-stage .screens-card > blockquote.quote-card padding (sm 2rem sm md) and the 13px words would need retuning to match; .screens-stage .screens-card .star-btn / .hide-btn tops; and two things that depend on the hanging gutter: .screens-grip-side ("the margin under the timecode", left: 0; top: 2.2rem; width: 3.6rem) would lie over the words, and the top row itself becomes the obvious grip (a title bar). .screens-seq sits on the top edge at left: var(--bn-space-lg) and would crowd the timecode once it is on the top row.
Other surfaces — the card is shared: the Quotes lens, the dashboard's featured quotes, the HTML export, focus mode (templates/focus-mode.css restyles blockquote.quote-card) and print (templates/print.css). The owner wants one card everywhere, so changing blockquote.css changes all of them at once; that is the intent, and the place to check each by eye. The sealed static renderer shares the CSS but its markup (theme/templates/quote_card.html) has the same shape, so it follows.
For C, add the grid rules (grid-template-areas: "tc spk" "text text" "tags tags", .quote-body { display: contents }) and the name truncation on .bn-speaker-badge-name, scoped to the card so the Sessions grid's badges are untouched. Better done in the DOM: move .speaker next to the timecode.
For D2, QuoteCard.tsx moves the timecode element into .badges as its first child and the three toggles to its end; atoms/toggle.css loses position: absolute for the card's toggles; .undo-btn needs display: none when not visible.
Trade-offs with editing, trimming, tag input and focus
Editing and trimming (crop/text mode, .quote-card.editing): the brackets replace the smart quotes inside .quote-text-wrapper, so every variant edits the same way. A, B, C and D2 give the bracket handles a wider column, which makes dragging them easier. D1 puts the timecode link immediately before the opening bracket: a click a few pixels left of [ plays the clip instead of starting a drag. .quote-card.editing .quote-text { min-width: 10rem } holds in all.
Tag input: opens in place of "+" inside .badges and its suggestion list is absolutely placed. Unaffected in A–D1. In D2 the row also holds the timecode and toggles, so at 270px the input wraps onto its own line sooner.
Focus and selection (.bn-focused, .bn-selected): both paint the card's background, shadow and left keyline (atoms/interactive.css), so they are layout-neutral and hold in every variant. With A's 8px gutter the selection keyline and the first letter are close; B's 16px is the same as today. Focus shows the eye (.quote-card.bn-focused .hide-btn); in A–C that now lands on the timecode's row.
Starred: the words take --bn-weight-starred (520), slightly wider; the starred column in the matrix shows it costs no extra lines at these widths.