Initially you really need a strong understanding of digital logic (not a language), in particular pipelines.
Once you have that stuff in your head you can turn to verilog (or vhdl or whatever) and learn how to map these ideas into the language
In System Verilog it's easy this is the only way to reliably make synthesisable flops:
bit a, b;
always @(posedge clk)
a <= b;
And you can make combinatorial logic 2 ways: wire c; bit d;
assign c = a&b;
always @(*)
d = a&b;
They'll make the same gates, notice the use of = vs <=, you typically use the always when you want something more complex"always X" just means loop waiting for X, '*' means "anything important changes"
That's it, the most important concepts you have to get your head around, everything else is just this at scale - also please ignore the async reset in the "Verilog is Weird" example - they tend to be timing nightmares in the real world, use a synchronous reset instead.
One more thing - Verilog is an early object oriented language - modules are objects - but they are static, the entire design can be elaborated at compile (or synthesis) time - why? because you can't new or malloc more gates on the fly on a real chip - almost everything in verilog is static by design (it does support local variables in functions but anything that's vaguely recursive wont make gates in synthesis)