You might find it helpful to think of it this way. In general your logic will have three different types of signals.
The first are those where the signal edges matters. These only provide timing information and are called 'clocks'.
The second are those where the value of the signal matter. These hold data, and when the data changes should depend on only the timing information from one 'clock' signal.
In general you want to use these type types of signals for FPGA work, and you should stick to these two as much as possible.
The third class is called "nightmares", "accidents waiting to happen", "async reset signals" and many other names.
They control both what will happen and when it will happen, and are always problematic and require careful analysis.
In your case, you used "cs" as a clock ("always @(posedge cs) begin"), and as data ("if (cs == 0)..."), and were updating "counter" based on timing information from two different clock signals ("cs" and "clk"). You needed to be clearer in your design about which signals are clocks, and signals are data (don't worry, everybody does this at the start!)
Sometimes the EDA tools are able to give you exactly what you asked for, but unless you have a very good reason and are very careful about it the results are not usually what you want, or contain hidden timing errors, seem to work non-deterministically, and/or have glitches.