I'm glad to hear you got it working! Sorry if my instructions were not quite on point. I have actually never worked with the M0 because I don't own one. My instructions were based on my experience with other Arduino SAMD boards. I know that some native USB Arduino boards have a special feature of the bootloader where the double reset causes the board to stay permanently in bootloader mode. I had assumed that all the SAMD boards have this feature. However, I know that there are some native USB boards (e.g. Leonardo) which don't have that feature. When you reset the board, the bootloader mode is activated for a short time, then it times out and runs the application. On those boards, the double reset doesn't do anything special; it's just the same as a single reset. On these boards, you need to time the reset correctly so that it goes into bootloader mode at the right stage of the upload (after the compilation finishes but before the search for the bootloader serial port has timed out). This is what you achieved by pressing the reset after starting the upload.
So it might be that the bootloader on the M0 doesn't have the double reset feature.
So just to make sure you understand what is going on (apologies if this is old news to you):
On the native USB boards like your M0, there is some code hidden in the Arduino core library that runs on the SAMD microcontroller in the background of your sketch and creates a CDC serial port. That serial port is used for communication with the computer (e.g. Serial Monitor). It is also used in the upload process in an interesting way. The Arduino IDE needs to trigger the bootloader before starting an upload. On the native USB boards, this is done by opening a serial connection to that CDC port at 1200 baud. The code running behind your sketch sees this as a special signal to reset the board and start the bootloader. The bootloader code also creates a CDC port. This is why you will usually see that a different port number is created when the bootloader is running than when the sketch is running. The downside to this system is that if there is something weird with the sketch code that breaks that USB CDC code running in the background, the board is "bricked" from further uploads. Luckily, if you know the reset trick you can easily recover it. This is different from the classic Arduinos like Uno, Mega, etc., which have a dedicated USB to serial chip. On those boards, there is no way for sketch code to break the upload.
I think this may be the reason why the original Zero (and the M0 Pro) has two USB ports. One of those has a USB to serial adapter chip, and it is recommended in the documentation to always use that port for uploads. The Zero also has a "Native USB port", which is more intended for things like keyboard or mouse emulation, which the programming port can't do. That's all well and good, but it adds quite a bit to the price of the board, and maybe makes it a bit more confusing to use. So I think that's why the newer Arduino boards only have the native USB port.
seems to me this should really be "downloading", but I guess that's not what the IDE programmers thought.
That's certainly a subject of much debate. "Upload" has always made the most sense to me, but I started with Arduino so I'm biased. I have since learned that there is precedent for using "download" instead. Well, as long as we all understand what we're talking about I'll just take the philosophy of "a rose by any other name".