- ContactsPage: drop whiteSpace:nowrap on the action cell; wrap the
Edit/History/Delete/⋮ buttons in a flex container with flex-wrap so they
reflow instead of forcing the table wider than the viewport; allow the
name/number/email cell to break long strings.
- index.css: td word-break:break-word + table max-width:100% as a guard.
- Sync the UI repo (ContactsPage/ContactHistory/MessagesPage implicit-any
annotations that unblock npm run build) into the frontend/ mirror.
- use flexbox space-between in .who
- name/number truncates with ellipsis
- menu pinned right with flex-shrink:0
- tighter button padding and dropdown gap
- ⋮ button beside contact name/number
- Call back uses tel: link with sanitised digits
- Lookup number opens Google search in new tab
- dropdown closes on outside click
- extract E.164 from angle brackets when present
- show 'Number: ...' at top of modal instead of readonly input
- use same sanitiseNumber() for message list callback links
- replace var(--bg-surface) with literal #0a0e17 in input CSS
- add -webkit-appearance:none to prevent native widget override
- apply to both main and .modal input rules
- vm_api.py: pure FastAPI JSON API on :8098 with CORS
- vm-api.service: systemd unit for API (replaces inline HTML vm_web.py for frontend)
- vm_web.py: kept intact as fallback; Apache now proxies /api/ -> :8098
- frontend/: Vite + React + TanStack Query scaffold
- Apache vhost updated: DocumentRoot -> frontend/dist, /api/ proxy, SPA fallback
- All original HTML pages still functional via :8099 during transition