Labels were inserted as normal DOM siblings with z-index set but
position left as the default "static" - z-index has no effect on
non-positioned elements, so any ancestor that establishes its own
stacking context (e.g. a position:relative logo wrapper with a
hover/link overlay, common in component libraries like Salesforce
LWC/SLDS) could paint over the label and swallow clicks intended for
it. Labels now get a real position:absolute anchored to the target
element's viewport position and are appended directly to
document.body, escaping any ancestor stacking context while still
scrolling correctly with the page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Some frameworks (e.g. Salesforce LWC) expose a .shadowRoot on elements
whose content is actually the same light-DOM subtree rather than a
real encapsulated tree. deepQueryAll's recursive shadow traversal
revisited that subtree once per nested "shadow" ancestor, so a single
image could get processed and labeled multiple times (observed: one
footer logo produced 5 identical OK badges). deepQueryAll now tracks
visited roots and elements so each is only ever processed once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Exclusions were keyed only by content identifier (src / role-img
label), so multiple identical images (or repeated icons) shared one
key and excluding one silently excluded all of them. Each occurrence
now gets a per-run instance number appended to the identifier, so
duplicates can be excluded individually while staying stable across
reloads.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
imageIdentifier() only checked currentSrc/src, which don't exist on
inline <svg role="img"> icons (common for social-media links). The
exclude click therefore silently no-op'd for those. Fall back to the
surrounding link's href or the element's aria-label as the identity.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>