Quote Anatomy

Composable atoms, molecules, and organisms that render quotes across Bristlenose. This is a living reference — if the design system changes, this page should be updated to match.

1. Atoms

Smallest reusable pieces. Each atom has a CSS file and a React component.

Timecode
CSS atoms/timecode.css
React components/TimecodeLink.tsx
Person Badge
p1    m1
CSS molecules/person-badge.css
React components/PersonBadge.tsx
Badge — All 7 Sentiments (AI)
frustration confusion doubt surprise satisfaction delight confidence
CSS atoms/badge.css (.badge-ai .badge-{sentiment})
React components/Badge.tsx variant="ai" sentiment="..."
Intensity Dots
2/3
CSS organisms/analysis.css (.intensity-dots-svg)
React AnalysisPage.tsx → IntensityDotsSvg
Quote Row (layout molecule)
[02:08] p1  The raw content layout.
CSS organisms/blockquote.css
React Shared layout

1b. Codebook Colour Palette

26 tag colours from 5 framework codebook sets. Toggle system dark mode to see saturated variants.

UX (blue) ux-1 ux-2 ux-3 ux-4 ux-5
Emotion (pink) emo-1 emo-2 emo-3 emo-4 emo-5 emo-6
Task (green) task-1 task-2 task-3 task-4 task-5
Trust (purple) trust-1 trust-2 trust-3 trust-4 trust-5
Opportunity (amber) opp-1 opp-2 opp-3 opp-4 opp-5
Custom ungrouped

1c. Interactive Badge States

Hover each badge to see the interaction. All pure CSS — no JS needed.

AI Badge — hover to delete
satisfaction    frustration
Hover → dims to 0.8, floating × circle fades in
User Tag — hover to delete
interaction design    onboarding flow
Hover → × button fades in (same visual as AI)
Proposed Badge (AutoCode) — hover to accept/deny
wireframe issue    credibility concern    anxiety trigger
Pulsates 0.50–0.78 opacity (3s). Hover → freezes at 1.0, reveals accept / deny
Add Tag Ghost — hover for blue
+
Hover → dashed border + text turn accent blue
Readonly Badge (signal cards)
interaction design   navigation
No interaction — display only. Used in signal card quotes

2. Composed Organisms

The same atoms composed in different containers for different contexts. Each organism adds its own chrome; the quote content is identical underneath.

Quote Card — Quotes page (full badge row) QuoteCard.tsx → blockquote.quote-card
[00:35] "Ah, it worked that time. Okay, and then beds." —  p2
satisfaction interaction design onboarding flow wireframe issue +
Chromebackground, left border, margin, radius, action buttons (edit, hide, star)
Badge rowAI sentiment + user tags (2 codebook sets) + proposed pulsating + add ghost
InteractionsHover card → badges 0.9→1.0, hide/edit visible. Hover badges → delete/accept/deny
CSSorganisms/blockquote.css (.quote-card) + molecules/{badge-row,quote-actions}.css
Signal Card Quote — Analysis page AnalysisPage.tsx → QuoteBlock → bare blockquote
Theme
Healthcare system navigation challenges
frustration
[02:08] p1  Because I thought the way I was treated wasn't right. That I wasn't able to see the surgeon again.
ChromeNone on blockquote — parent .signal-card-quotes panel provides containment
No left borderCard accent bar (::before) is the only colour signal
CSSorganisms/blockquote.css (base only) + organisms/analysis.css (margin override)
Sequence Quotes — consecutive quotes from same speaker AnalysisPage.tsx → QuoteBlock + seq-first/middle/last
Theme
Positive onboarding experience
satisfaction
[01:22] p3  The setup was really straightforward.
[01:25] I didn't need to look anything up.
[01:28] It just worked, which was refreshing.
Sequence border2px accent left border spans the group; solo quotes have no border
SpeakerShown on seq-first only; middle/last are continuations
TimecodeFaded to 60% opacity on continuations
Cell Tooltip — heatmap hover AnalysisPage.tsx → CellTooltip (separate implementation)
Because I thought the way I was treated wasn't right. That I wasn't able to see the surgeon again. p1
The waiting time was unacceptable. Nobody told me what was happening. p3
ChromeMinimal card with shadow, accent bar, no shared atoms
OpportunityCould reuse Timecode + PersonBadge atoms in future
Canvas Sticky — future Miro-style drag surface Not yet implemented — wireframe placeholder
Because I thought the way I was treated wasn't right. That I wasn't able to see the surgeon again unless I was having another hernia operation.
The setup was really straightforward. I didn't need to look anything up.
ChromeSquare card, top accent bar, grip strip (drag handle), shadow
Atoms reusedTimecode, PersonBadge, quote text — same atoms, different container
ValidatesComposition > flags — completely different chrome, same inner atoms

3. Layer Diagram

Three layers of a single Quote Card, showing how CSS, React, and data map to each other.

Quote Card (quotes page)

Data (API)
quote.text quote.start_timecode quote.participant_id
quote.sentiment quote.tags[] quote.proposed_tags[] quote.is_starred
React
<blockquote> className="quote-card"
  <TimecodeLink seconds />
  <PersonBadge code role />
  <EditableText text />
  <Badge variant="ai" sentiment />
  <Badge variant="user" colour="getTagBg(set,idx)" /> × N
  <Badge variant="proposed" rationale onAccept onDeny /> × N
  <Toggle type="star" /> <Toggle type="hide" />
CSS
.quote-card ← organisms/blockquote.css (bg, border, radius)
.quote-row .quote-body ← organisms/blockquote.css (flex layout)
.timecode ← atoms/timecode.css
.badge-ai .badge-user .badge-proposed ← atoms/badge.css
.badges ← molecules/badge-row.css (flex row, opacity)
.star-btn .hide-btn ← atoms/toggle.css
.starred ← molecules/quote-actions.css

Signal Card Quote (analysis page)

Data (API)
quote.text quote.startSeconds quote.pid
quote.intensity quote.tagNames[] quote.sessionId
React
<blockquote> className="{seq-*}" (or none)
  <a className="timecode">
  <PersonBadge code />
  <span className="quote-text">
  <Badge variant="readonly" /> × N (tag signals only)
  <IntensityDotsSvg value />
CSS
blockquote ← organisms/blockquote.css (base: margin + padding only)
.signal-card-quotes blockquote ← organisms/analysis.css (margin override)
.quote-row .quote-body ← organisms/blockquote.css (flex layout)
.badge-readonly ← atoms/badge.css
.seq-* ← organisms/analysis.css (sequence borders)

Source: docs/mockups/quote-anatomy.html — CSS atoms from bristlenose/theme/, React components from frontend/src/. Last updated with the blockquote → .quote-card refactor (Feb 2026).