8d040314a3
The global childList observer scheduled replaceIconsInElement() with no scope on ANY node insertion — including bare text nodes — so every notification-bell progress tick during an upload and every infinite-scroll batch re-scanned the whole document with an attribute substring selector. Cost grew with total DOM size (5-10k nodes), not with what was inserted. Queue the added element roots per animation frame and scan just those subtrees (an inserted <i> itself is caught via its parent). Text-node churn no longer triggers any scan at all. The icon replacement is idempotent, so overlapping roots are harmless. https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx