If software design is how you assemble lines of code, system design is how you assemble services. The primitives of software design are variables, functions, classes, and so on. The primitives of system design are app servers, databases, caches, queues, event buses, proxies, and so on.
Good system design is not about clever tricks, it’s about knowing how to use boring, well-tested components in the right place. I’m not a plumber, but I imagine good plumbing is similar: if you’re doing something too exciting, you’re probably going to end up with crap all over yourself.
The most elegant solution here is Haskell’s
map words $ lines text
Here, your program is constructed left to right.
There’s a principle in design called progressive disclosure. The user should only be exposed to as much complexity as is neccessary to complete a task. Additionally, complexity should naturally surface itself as it is relevant to the user. You shouldn’t have to choose a font family and size before you start typing into Word, and options to change text wrapping around images should appear when you add an image.