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)
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.
[ 00:35]
"Ah, it worked that time. Okay, and then beds." —
p2
satisfaction
interaction design×
onboarding flow×
wireframe issue✓ ✗
+
✎
🚫
★
Chrome background, left border, margin, radius, action buttons (edit, hide, star)
Badge row AI sentiment + user tags (2 codebook sets) + proposed pulsating + add ghost
Interactions Hover card → badges 0.9→1.0, hide/edit visible. Hover badges → delete/accept/deny
CSS organisms/blockquote.css (.quote-card) + molecules/{badge-row,quote-actions}.css
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.
Chrome None on blockquote — parent .signal-card-quotes panel provides containment
No left border Card accent bar (::before) is the only colour signal
CSS organisms/blockquote.css (base only) + organisms/analysis.css (margin override)
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 border 2px accent left border spans the group; solo quotes have no border
Speaker Shown on seq-first only; middle/last are continuations
Timecode Faded to 60% opacity on continuations
Chrome Minimal card with shadow, accent bar, no shared atoms
Opportunity Could reuse Timecode + PersonBadge atoms in future
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.
Chrome Square card, top accent bar, grip strip (drag handle), shadow
Atoms reused Timecode, PersonBadge, quote text — same atoms, different container
Validates Composition > 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).