I resisted Tailwind for two years. My reasoning was principled: separation of concerns, DRY styles, semantic class names. All the right arguments. Then I joined a team using it and spent a month being wrong about everything.
The thing that changed my mind wasn't the developer experience hype. It was reading a component and immediately knowing exactly how it looked without jumping to a CSS file. Co-location of concerns, not separation.
What I actually changed
Most of my old patterns mapped cleanly. BEM blocks became components. Modifiers became conditional classes. The one pattern I genuinely miss is complex selectors — :has(), sibling combinators, attribute selectors — which feel awkward as arbitrary variants.
What Tailwind doesn't fix
Design tokens. Tailwind gives you a scale but not a system. On any real project I end up building a tokens.ts anyway — spacing, color roles, type scales — and wiring them into the config. At that point, the utility classes are just a shorthand for a system you still had to design.
The framework is a tool, not a substitute for design thinking. I've seen beautiful Tailwind codebases and nightmarish ones. The difference was always the designer, not the framework.