width: auto on Static expands to content width before clamping,
so self.size.width matched content and truncation never fired.
Switch to fixed width with dynamic resize, use content_size to
exclude padding/border from width calculations.
Sidebar uses auto width (min 16, max 32) instead of fixed 24.
Channel and user names truncate with ellipsis at widget boundary.
Status bar adapts format based on available width. Resize events
trigger re-render of width-aware widgets.
Start AudioPipeline on server connect, send loop polls capture
queue, PTT toggles mic encoding, incoming sound queued for playback.
Audio failure logs to chatlog without crashing.
Connect to server on mount via @work(thread=True). Bridge pymumble
callbacks to Textual messages (ServerConnected, ServerDisconnected,
TextMessageReceived, ServerStateChanged). Render live channel/user
tree recursively. Send text on input submit. Clean disconnect on quit.
Convert connect/disconnect to blocking calls (pymumble is synchronous).
Remove asyncio loop coupling. Add set_dispatcher() for marshalling
callbacks into the host event loop. Register all pymumble callbacks:
connected, disconnected, user/channel CRUD, text message, sound.