$(…) is a command substitution (“process substitution” is <(…) and the like). Variable substitutions and command substitutions occur in the same pass, from left to right in the string. The only things that occur on the result of these substitutions are word splitting and globbing.
So x='$(id)' sets x to the 5-character string $(id). Then, to run $x, the shell replaces $x by the value $(id). This does not contain any whitespace or globbing character so it is treated as a command name.
Contrast with:
x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x
Assuming that the file /none/id doesn't exist but /usr/bin/id does, the echo command expands to three words: echo (obviously), /none/@(id) (the glob pattern /none/@(id) doesn't match anything so it's left unchanged), and /usr/bin/id (the glob pattern /usr/bin/@(id) matches one file, so it's replaced by the one-element list of matches).
In the bash manual, the relevant sentence is at the beginning of the Shell Expansions section.
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
Everything between two semicolons is one pass. Each pass works on the result of the previous pass.
Beware that a single sentence (even a complex one like the one I cited above) can't tell the whole story. Shell semantics is convoluted. I doubt that any shell's manual has the details of all the corner cases. The POSIX specification is more formal but doesn't cover bash-specific extensions and even it leaves some really odd cases undefined.