The HTML already holds the final value: <span class="ctup-value" data-target="8547">8,547</span>. The script looks for every .ctup-value[data-target] inside a .fx-0223-root, resets the display to 0, then waits until the number is half visible (IntersectionObserver, threshold 0.5). It then counts up to data-target over 2 seconds, slowing down at the end (cubic ease-out), and never starts again.
The number of decimals comes from data-target itself: 6.4 shows one decimal, 4.85 shows two, 8547 none. The format follows the closest lang attribute (usually the one on <html>) through Intl.NumberFormat: "8,547" and "6.4" on an English page, "8 547" and "6,4" in French. Digits share the same width (tabular-nums), so the block does not wobble while counting.
Every number is handled on its own: several counters in one root, several roots in the page, each one starts when it becomes visible. The script declares nothing on window. A number revealed later (tab, collapsed panel, hidden removed) counts at the moment it appears.
Dependency-free JavaScript (about 2 KB) and CSS variables. Measured on 08/11/2026 in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): counting on appearance, a counter further down waiting for the scroll, two copies, 390 px, reduced motion, French and English formats, no error. Versions taken from @mdn/browser-compat-data: IntersectionObserver sets the minimum.
Chrome 51+✓ Full (measured)
Firefox 55+✓ Full (measured)
Safari 12.1+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
iOS Safari 12.2+✓ Not checked on a real device
Android Chrome 51+✓ Full (Chromium engine)