The key point is that offers are referenced/consumed via a URL, similar to a webpage. They are hosted in a model for sure, but that's irrelevant to the act of consuming.
juju offers operates on a model because it is used by an admin to see what relations exist to offer in that model and provides the data needed to make decisions about suspending/resuming a connected consumer, removing a misbehaving consumer connection etc. NB juju offers and list-offers are aliases for the same command.
juju find-offers operates on a controller because it is intended to be a way to search for any available offers matching a given interface or endpoint or even offers contained in a given controller and/or model (you specify a URL fragment).
juju show-offer allow doesn't operate on a model because it takes a full offer URL as an argument. The URL specifies the controller and model and offer name.
juju consume also takes a URL as an argument. You can leave off bits of the URL that aren't necessary, eg if both the consuming model and offering model are in the same controller you don't have to specify the controller part of the URL
To clarify a little more the semantics....
The key point is that offers are referenced/consumed via a URL, similar to a webpage. They are hosted in a model for sure, but that's irrelevant to the act of consuming.
juju offers operates on a model because it is used by an admin to see what relations exist to offer in that model and provides the data needed to make decisions about suspending/resuming a connected consumer, removing a misbehaving consumer connection etc. NB juju offers and list-offers are aliases for the same command.
juju find-offers operates on a controller because it is intended to be a way to search for any available offers matching a given interface or endpoint or even offers contained in a given controller and/or model (you specify a URL fragment).
juju show-offer allow doesn't operate on a model because it takes a full offer URL as an argument. The URL specifies the controller and model and offer name.
juju consume also takes a URL as an argument. You can leave off bits of the URL that aren't necessary, eg if both the consuming model and offering model are in the same controller you don't have to specify the controller part of the URL