Tagg the Builder saysThe <script> element runs JavaScript; place it at the end of <body> or use defer so the DOM exists first.
<script> either holds inline JS or loads a file with src. Where you put it matters: a script in the head runs before the body exists, so DOM lookups return nothing.
The fixes: put scripts just before </body>, or add defer to a head script so it waits for the DOM. Use async for independent scripts (analytics) that don't touch your DOM.
Power-ups you unlock
<script src="..."> loads a file · inline <script> runs code
Scripts in <head> run before the DOM is built
defer waits for the DOM; async runs as soon as it loads
Classic spot: just before </body>
The Unclosed Tag attacks — common mistakes
Querying elements in a head script before they exist → null
Using async for a script that depends on the DOM or other scripts
Blocking render with a big synchronous script in the head
Boss battleMove the <script> from the bottom into the <head> and watch the button lookup fail. Then add defer to fix it.
Example code
<!doctype html>
<html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff">
<button id="b">click</button>
<p id="out"></p>
<script>
document.getElementById('b').onclick = () =>
document.getElementById('out').textContent = 'the script found the button.';
</script>
</body></html>