Symptom

On first launch (no nodes, FTUE active), the centred “No nodes yet” / “Add a server to get started” empty-state text appeared over the top of the Terms-of-Service and PIN-entry dialogs rendered inside the avatar speech bubble.

Root cause

In ClientScreen, Box children are stacked in composition order: DisplayNodes (which contains AvatarWithSpeechBubble and its FTUE speech bubble) is the first child; the “No nodes yet” empty-state block is the second child. Later children in a Box paint on top of earlier ones, so the empty state physically covered the dialog.
The guard on the empty state (shouldShowNoNodesEmptyState && swarmStable) had no awareness of the ongoing FTUE phase; it fired whenever the swarm had stabilised with no servers or client children, which is exactly the state during initial FTUE.

Fix

Computed isFtueActive in ClientScreen by reading OnboardingStore.tosAccepted() and ClientPinStore?.bearerToken() (the same stores AvatarWithSpeechBubble uses) and gated the empty state on !isFtueActive. Extracted isNoNodesEmptyStateVisible() as a testable pure helper that combines the swarm check with the stabilisation and FTUE guards. Added four regression tests in NoNodesEmptyStateTest.

Prevention