That's only weird to you because C doesn't do it.
For someone starting in one of those languages, it simply makes sense that I can use any variable in scope. (Stack allocation? What is this sorcery you speak of?)
Because stack allocation has nothing to do with C, C is not explicit about doing it (except alloca) just like most other languages, and other languages use it just like C does, including C# with its closures and async/await. It even has stackalloc.
In C, a variable's lifetime is limited to the current function call. The natural implementation of C is to track both function calls and variables on stack structure with statically determined offsets. Thus, C has stack-allocated variables.
Since a Clojure variable's lifetime is not limited to the current function call, C's implementation details aren't relevant. Stack-allocated variables are a bizarre notion.
In reality it comes from trying to apply how that language works in normal cases (in the absence of those features), and the features requiring special compiler magic to work.
Yes if variable lifetime is as you describe in Clojure then that sentence doesn't make sense for Clojure.
As I've already told someone else, it is unlikely that learning C at some point in your life (not as my first language, not as the language I use professionaly, not even in my top 3 most used languages) permanently cripples your ability to understand other languages.
In any non-systems language you don't need to know (and knowing it doesn't help you with anything) this stack sorcery you're talking about.
You can mess with the stack in C, you can also mess with the stack in C#. But you don't have to, and normally you don't. You use it in a completely transparent manner, not caring where the compiler decides to put your data.
When it comes to stack allocation, in C this is the compiler's decision and in JS this is the execution engine's decision.
In JS, that quote makes perfect sense, and the answer is: the engine checks what can be safely put on the stack, and the stuff that is closed over is stored on the heap to avoid losing it when the function returns.