diff --git a/frontend/src/lib/timeline/GlyphLabel.svelte b/frontend/src/lib/timeline/GlyphLabel.svelte
new file mode 100644
index 00000000..ddc367c1
--- /dev/null
+++ b/frontend/src/lib/timeline/GlyphLabel.svelte
@@ -0,0 +1,12 @@
+
+
+{glyph}
+{label}
diff --git a/frontend/src/lib/timeline/GlyphLabel.svelte.spec.ts b/frontend/src/lib/timeline/GlyphLabel.svelte.spec.ts
new file mode 100644
index 00000000..32930cb3
--- /dev/null
+++ b/frontend/src/lib/timeline/GlyphLabel.svelte.spec.ts
@@ -0,0 +1,15 @@
+import { describe, it, expect, afterEach } from 'vitest';
+import { cleanup, render } from 'vitest-browser-svelte';
+import GlyphLabel from './GlyphLabel.svelte';
+
+afterEach(() => cleanup());
+
+describe('GlyphLabel', () => {
+ it('renders the glyph aria-hidden with an sr-only label sibling', () => {
+ render(GlyphLabel, { glyph: '✉', label: 'Brief' });
+ const hidden = document.querySelector('[aria-hidden="true"]');
+ expect(hidden?.textContent).toBe('✉');
+ const srOnly = document.querySelector('.sr-only');
+ expect(srOnly?.textContent).toBe('Brief');
+ });
+});
diff --git a/frontend/src/lib/timeline/LetterCard.svelte b/frontend/src/lib/timeline/LetterCard.svelte
index a093ab30..4f44a6b4 100644
--- a/frontend/src/lib/timeline/LetterCard.svelte
+++ b/frontend/src/lib/timeline/LetterCard.svelte
@@ -1,6 +1,7 @@