Compositions that defer gsap.timeline() registration past DOMContentLoaded
(via setTimeout, template instantiation, or dynamic script loading) hit a
race where __renderReady stays false forever:
1. At DOMContentLoaded, __hfTimelinesBuilding is false — init.ts skips
the hf-timelines-built listener and sets __renderReady = true
2. The deferred script runs, calls gsap.timeline().to() which sets
__hfTimelinesBuilding = true via the batching proxy
3. The deferred maybePublishRenderReady() sees building=true, sets
__renderReady = false, but never registers a listener to retry
4. __renderReady stays false, __hf.duration returns 0, pollHfReady
times out with "Composition has zero duration"
Fix: when maybePublishRenderReady encounters __hfTimelinesBuilding=true,
register a one-shot hf-timelines-built listener to retry — matching the
pattern already used at init time for the synchronous batching case.
Closes#1260