Every reactive audio player on the web keeps a small script whose only job is to listen for play and pause and copy that into a class name. Chrome 152 makes the state a selector. Add :has() and it stops being about the element: the whole page can react to the media. Nothing on this page runs. Press play and watch it change anyway.
The disc spins, the bars rise, the border warms and the word changes. All of it is CSS matching on the <audio> element below it. Hit mute and the colour drains out. Scrub and the border flashes cool.
Your browser does not have these selectors. You are looking at the static fallback, which is the honest thing to show: the disc sits still and dull, the bars hold a frozen pattern, and the readout says IDLE no matter what the player is doing. The pseudo-classes are Chrome 152, which was in beta when this page was written. Everything below still explains the feature, and the readout in section 04 lists exactly what you do and do not have.
:has(audio:playing)
The transport is the browser's own controls, and that is deliberate. Styling from state is free now; causing state still needs script. A page with no JavaScript can react to a player perfectly and cannot build one, so this shows the half that actually changed.
The before is not complicated, it is just load-bearing: a listener pair, a class toggle, and a bug the first time someone mutes from the OS instead of your button.
Before
// and one of these per state, forever const a = document.querySelector('audio'); a.addEventListener('play', () => root.classList.add('is-playing')); a.addEventListener('pause', () => root.classList.remove('is-playing')); a.addEventListener('volumechange', () => root.classList.toggle('is-muted', a.muted)); // …then remember to remove them all
After
.stage:has(audio:playing) .disc { animation-play-state: running; } .stage:has(audio:muted) .bars i { background: linear-gradient( 180deg, var(--dim), transparent); } /* no listeners, nothing to tear down, and OS-level mute is picked up too */
Both are real selectors in 152 and both are wired into the stylesheet above. Neither will ever fire on this page, because the audio is an inline data: URI: it is already in memory, so it never waits on a network and never enters a wait state.
A timed animation on the buffering chip would look identical to the real thing on a screenshot. It would also be the one lie that makes every other number on this page worth nothing.
The :buffering and :stalled rules are in the stylesheet, doing nothing. Point the same CSS at a slow network source and they light up with no other change.
A buffering spinner used to mean listening for waiting and playing and racing them against a timeout. Now it is a selector that cannot desynchronize from the element.
Detected with @supports selector(…), so this readout needs no JavaScript either. FALLBACK means that section is showing you the degraded version.
rgb(from … / alpha(8%)). Fallback: hand-written rgba() of the same colour, visually identical.