I'm in the same boat.
I don't use lit-element, it's too heavy for me.
lit-html, on the other hand, is wonderful and rock solid.
I typically do light dom components, rendered with lit-html. Simple classes that extend HTMLElement.
When I want reactive style, I add setters that call render(). When I want imperative, I add class functions.
All my components generally take care of themselves and are mostly encapsulated, they'll generally have a init() method that loads the data they need, and calls a setter which kicks off the render cycle.
Alternately, data will be passed from a parent component via a property, and that'll also kick off the render cycle.
In many cases I do a combination of the two in order to support deep linking.
I'll mix and match design systems sometimes, depending on the payload weight. Ionic, shoelace, etc...
The Vaadin router ties everything together beautifully.
I also have a small state utility called ApplicationState[1] that I use for the edge case of cross-component communication and triggering. It provides a graph-based approach to notifications/state change.
I've been using this approach for several years with success, with deeply complex and large applications and small lightweight tiny footprint apps.
[1] https://claytongulick.github.io/applicationstate/