webui: implement explicit initial render detection using State.message_count

Add explicit initial load completion detection to SketchTimeline component using
State.message_count to determine when all existing messages have been loaded
and the timeline is ready for initial render.

Implementation Changes:

1. DataManager Enhancement (data.ts):
   - Add expectedMessageCount and isInitialLoadComplete state tracking
   - Add 'initialLoadComplete' event type to DataManagerEventType union
   - Add checkInitialLoadComplete() method to validate completion state
   - Add handleInitialLoadComplete() event emission with message counts
   - Handle empty conversation edge case (message_count: 0) with immediate completion
   - Reset initial load state on connection establishment to handle reconnection
   - Add getIsInitialLoadComplete() and getExpectedMessageCount() getters

2. Timeline Component Enhancement (sketch-timeline.ts):
   - Add isInitialLoadComplete state property for render control
   - Add dataManager property reference for event listener setup
   - Add handleInitialLoadComplete() event handler with console logging
   - Update render logic to show loading indicator until initial load complete
   - Apply 'view-initialized' CSS class when initial load completes
   - Only render messages and thinking indicator after initial load completion
   - Set up DataManager event listeners in updated() lifecycle hook
   - Clean up event listeners in disconnectedCallback() lifecycle hook

3. App Shell Integration (sketch-app-shell.ts):
   - Pass dataManager reference to sketch-timeline component property
   - Enable timeline component to receive initial load completion events
   - Maintain existing data flow while adding explicit completion detection

4. Demo Mock Enhancement (handlers.ts):
   - Initialize currentState with correct message_count based on initial messages
   - Ensure proper message_count synchronization in SSE stream simulation
   - Handle empty conversation demo scenario with accurate state

5. Enhanced CSS Styling (sketch-timeline.ts):
   - Add opacity-based transitions for message appearance
   - Show loading indicator before initial completion
   - Hide message content until view-initialized class is applied
   - Smooth transition from loading to content display

Technical Benefits:
- Eliminates reliance on implicit 'first message means streaming started' detection
- Provides explicit completion signal when all existing messages are loaded
- Handles edge cases like empty conversations (0 messages) immediately
- Prevents flash of incomplete content during initial load
- Enables proper loading states and smooth transitions
- Supports reconnection scenarios with state reset

User Experience Improvements:
- Clear loading indicator until conversation is fully loaded
- Smooth transition from loading to content display
- No flash of partial message lists during initial load
- Consistent behavior across different conversation sizes
- Better feedback during network delays or large conversation loads

Edge Case Handling:
- Empty conversations (message_count: 0) marked complete immediately
- Messages arriving before state handled gracefully
- Reconnection scenarios reset initial load detection
- Race conditions between state and message delivery resolved

This replaces the implicit initial load detection with explicit State.message_count
based completion detection, providing more reliable initial render timing and
better user experience during conversation loading.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s5126c2705d6ad6bak
diff --git a/webui/src/web-components/sketch-app-shell.ts b/webui/src/web-components/sketch-app-shell.ts
index d3bf00d..b0177a0 100644
--- a/webui/src/web-components/sketch-app-shell.ts
+++ b/webui/src/web-components/sketch-app-shell.ts
@@ -1408,6 +1408,7 @@
                 .firstMessageIndex=${this.containerState?.first_message_index ||
                 0}
                 .state=${this.containerState}
+                .dataManager=${this.dataManager}
               ></sketch-timeline>
             </div>
           </div>