How/where exactly does it store the user's private keys?

The initial reaction that I have to client-side encryption with a web browser is: how does the client fetch/obtain the encryption key? (For signing outbound messages, or decrypting/verifying inbound.) Local storage wouldn't be appropriate as the sole storage for something like an asymmetric keypair, and it wouldn't provide the behavior that users expect: being able to log in and use a service from any web browser.

No one interacts with a web browser in such a way that it would be appropriate for the browser's local state to be the sole storage of something important like a private key. So this necessitates a service that the client interacts with during login to fetch its private key.

If you can log in with a browser, then that implies that you're fetching the key from somewhere. In the context of hosted Gmail, then that means that Gmail will be storing and providing your key. In which case it's nominally client-side encryption -- and the system that stores and provides your key might be totally separate from the email systems (and tightly controlled) -- but it's still not what I'd think of as client-side encryption generally. It's not really client-side encryption if the service that you're using to store data is the same service (from your perspective) as the one that stores/provides your key (those responsibilities might be separated from an implementation perspective, but they aren't from a user's perspective).

The service can employ various techniques like encrypting its copy of my private key using a symmetric key derived from my passphrase (and then discarded) -- and this decryption could perhaps be done client-side in the browser -- but ultimately the service still has the ability to obtain my key (at time of next login, if not any time).

If the service that provides a client-side encryption key could be divorced from a particular use-case -- e.g., if I could use my own pluggable key-providing service with Gmail, which my browser uses to fetch my key on login -- then the model would make a bit more sense. (You'd still have to trust a service like Gmail not to steal your key, but at least you don't have to trust it to store the key as well.)

Would it be possible to implement a standardized pluggable key server model? It seems plausible. Imagine that there was a standard HTTP protocol for this purpose, kind of like how WebAuthN is standardized. I log into Gmail, link it to my key server <https://keys.jcrites.example.com>, verify the connection, and then when logging into Gmail, then the web page is allowed to make HTTPS calls to <https://keys.jcrites.example.com> to either fetch my asymmetric key, or alternatively make calls to decrypt or encrypt specific content.

In the former case, it implements client-side encryption using a key server I control, while trusting Gmail not to misuse the key; in the latter case, it implements encryption using a keyserver that I control, and makes remote calls for each encryption operation. In that case Gmail would never have my key, although while browsing Gmail.com it could probably make arbitrary requests to the key server to perform operations using the key -- but you could log what operations are performed.