diff --git a/frontend/src/lib/messages-extra.ts b/frontend/src/lib/messages-extra.ts
new file mode 100644
index 00000000..799999b6
--- /dev/null
+++ b/frontend/src/lib/messages-extra.ts
@@ -0,0 +1,37 @@
+/**
+ * Extra message functions for i18n keys added after the last paraglide compile.
+ *
+ * TODO: Remove this file once the root-owned paraglide files in src/lib/paraglide/
+ * are regenerated (run `npm run dev` or the paraglide compile step as the owning user).
+ * At that point, these functions will be generated into _index.js and the components
+ * that import from here should switch back to importing from $lib/paraglide/messages.js.
+ *
+ * Note: these fall back to German only — locale switching is handled by the generated
+ * paraglide files, not this shim.
+ */
+
+// Svelte auto-escapes interpolated values — do not use {@html} with these strings.
+
+export const conv_hint_single_person = (inputs: { name: string }) =>
+ `Alle Briefe von ${inputs.name} — wähle einen Korrespondenten oben um einzugrenzen`;
+
+export const conv_hint_single_person_filtered = (inputs: {
+ name: string;
+ from: string;
+ to: string;
+ sortLabel: string;
+}) => `Alle Briefe von ${inputs.name} · ${inputs.from}–${inputs.to} · ${inputs.sortLabel}`;
+
+export const conv_strip_period = () => 'Zeitraum';
+export const conv_strip_from_placeholder = () => 'Von…';
+export const conv_strip_to_placeholder = () => 'Bis…';
+export const conv_strip_all_correspondents = () => 'Alle Korrespondenten';
+export const conv_strip_sort_newest = () => 'Neueste';
+export const conv_strip_sort_oldest = () => 'Älteste';
+export const conv_suggestions_heading = () => 'Häufigste Korrespondenten';
+export const conv_suggestions_all_label = (inputs: { name: string }) =>
+ `Alle Korrespondenten von ${inputs.name}`;
+export const conv_letters_count = (inputs: { count: number }) => `${inputs.count} Briefe`;
+export const conv_empty_search_placeholder = () => 'Person suchen…';
+export const conv_empty_recent_label = () => 'Zuletzt geöffnet';
+export const conv_no_party = () => '—';
diff --git a/frontend/src/routes/korrespondenz/CorrespondentSuggestionsDropdown.svelte b/frontend/src/routes/korrespondenz/CorrespondentSuggestionsDropdown.svelte
new file mode 100644
index 00000000..e304cb4c
--- /dev/null
+++ b/frontend/src/routes/korrespondenz/CorrespondentSuggestionsDropdown.svelte
@@ -0,0 +1,129 @@
+
+
+
handleKeydown(e, e.currentTarget as HTMLElement)}
+>
+
+
+ {conv_suggestions_heading()}
+
+
+
+ {#if !loading}
+ {#each results as person (person.id)}
+
onselect(person.id)}
+ onkeydown={(e) => e.key === 'Enter' && onselect(person.id)}
+ >
+
+
+ {getInitials(person)}
+
+
+ {person.lastName}, {person.firstName}
+
+
+ {/each}
+ {/if}
+
+
+
+
+
+
onselect('')}
+ onkeydown={(e) => e.key === 'Enter' && onselect('')}
+ >
+ {conv_suggestions_all_label({ name: senderName })}
+
+
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte b/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte
new file mode 100644
index 00000000..0ff49bbf
--- /dev/null
+++ b/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
Korrespondenz durchsuchen
+
+
+
+ Wähle eine Person aus dem Archiv um deren Briefe zu sehen — mit oder ohne Korrespondent.
+
+
+
+
+
+
+
+
+
+ {#if recentPersons.length > 0}
+
+
+ {conv_empty_recent_label()}
+
+
+ {#each recentPersons as person (person.id)}
+
+
+ {/each}
+
+
+ {/if}
+
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte b/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte
new file mode 100644
index 00000000..08c9a5ac
--- /dev/null
+++ b/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte
@@ -0,0 +1,135 @@
+
+
+
+
+
+ {conv_strip_period()}
+
+
+
+
onapplyFilters()}
+ placeholder={conv_strip_from_placeholder()}
+ aria-label="Von"
+ class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border px-1 text-xs focus:outline-none sm:min-h-0"
+ class:border-[#002850]={!!fromDate}
+ class:text-[#333]={!!fromDate}
+ class:border-[#D1D5DB]={!fromDate}
+ class:text-[#AAA]={!fromDate}
+ class:italic={!fromDate}
+ />
+
+
–
+
+
+
onapplyFilters()}
+ placeholder={conv_strip_to_placeholder()}
+ aria-label="Bis"
+ class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border px-1 text-xs focus:outline-none sm:min-h-0"
+ class:border-[#002850]={!!toDate}
+ class:text-[#333]={!!toDate}
+ class:border-[#D1D5DB]={!toDate}
+ class:text-[#AAA]={!toDate}
+ class:italic={!toDate}
+ />
+
+
+
+ {conv_letters_count({ count: documentCount ?? 0 })}
+
+
+
+
+
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte b/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte
new file mode 100644
index 00000000..1a3b22ba
--- /dev/null
+++ b/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte
@@ -0,0 +1,87 @@
+
+
+
+
+
+
onapplyFilters()}
+ />
+
+
+
+
+
+
+
+
onapplyFilters()}
+ />
+ {#if !receiverId}
+
+ — optional
+
+ {/if}
+
+
diff --git a/frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte b/frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte
new file mode 100644
index 00000000..9bb49308
--- /dev/null
+++ b/frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte
@@ -0,0 +1,38 @@
+
+
+
+ 📋
+
+ {#if hasDateFilter}
+ {conv_hint_single_person_filtered({
+ name: senderName,
+ from: fromDate ?? '',
+ to: toDate ?? '',
+ sortLabel
+ })}
+ {:else}
+ {conv_hint_single_person({ name: senderName })}
+ {/if}
+