Code doesn't necessarily need to be clean. We've had, like, two decades of "do clean code" and a lot of the time that mentality is shit. Putting stuff in a separate file and introducing layers and layers of abstractions to keep things "clean" doesn't always make it so. Often, it makes the code more complex, and makes behavior difficult to reason about.
The big problem with Vanilla CSS is that's it's sort of like Perl. It's a read-only language in practice.
Yes, theoretically, you can have perfect semantic CSS classes and use those. In practice, not every button is the same and you'll need slightly different styling in different places.
Yes, we could go in and change the .button class. But who is using the .button class? Where is it used? Nobody knows, and you can't find out. So editing that class is EXTREMELY risky. I have seen many an entire application break because some dev decided to edit CSS. The bigger the application, the bigger the risk.
Where I work, we have 1500 devs. Does anyone know the complete set of usecases a CSS class would have? No. Even if I gave you a month to research it, you would not find out. So you cannot edit CSS classes, it's far too risky.
So, the result is that everyone just tacks on to the end of the CSS. And now, in your clean code world, you have 50 different button classes. Um... whoops.
If you want to compartmentalize, what you can do is use components, in whatever backend/frontend framework you have. You can have the component have their own state and allow users of the component to change parts of it. Then, it doesn't matter how "unclean" the tailwind is - because you'll almost never see it. But if you need to change it, you can, without destroying the entire application. No more 50 button classes, and no more read-only implementations.