app/map/page.tsx
Removed IncidentCard component and the incidents grid below the map — the on-map sidebar inside MapView is the single display
Moved kiosk exit button from top-3 left-3 (overlapping zoom controls) to bottom-[5.5rem] left-3
components/MapView.tsx
Fixed popup "View incident →" link — adds stopPropagation() + window.location.href to prevent Leaflet intercepting the click
Added "View details →" link on each sidebar incident card so you can navigate from the map panel without opening a popup
Added "News Alerts" overlay layer (placeholder, ready for RSS/feed integration)
lib/types.ts
Added preferred_token_id?: string | null to SystemRecord
lib/c2api.ts
Added setPreferredToken(tokenId, systemId) calling PUT /tokens/{tokenId}/prefer/{systemId} (backend already existed)
app/systems/page.tsx
Added PreferredTokenPanel component — loads the token pool lazily on expand, shows radio buttons to set/clear the preferred token, displayed on each system card above the AI flags panel
When the induction loop proposes a new vocabulary term, it now records
which sampled call(s) most likely produced the suggestion. Admins see
a collapsible "▶ source" player under each pending term showing the
audio clip and transcript, so they can hear what was actually said
before approving or dismissing.
- vocabulary_learner: track sampled call docs, attach source_call_ids
to each pending term via word-overlap search with fallback
- types: VocabularyPendingTerm.source_call_ids?: string[]
- c2api: add getCall(id) using existing GET /calls/{call_id} endpoint
- VocabularyPanel: SourceCallPlayer component — lazy-loads call on
first expand, shows audio controls + transcript snippet