The answer lies in this line here stuff = input_box1.handle_event(events)
The screen that was initially passed to handle_events, but once pygame.quit() is called the screen variable in input_box1 was not updated.
Changing the function to pass in the new screen surface fixed the issue.
I use a loop based on https://gafferongames.com/post/fix_your_timestep/
It renders as fast as possible and only updates when enough time has passed. This keeps your update code incredibly simple because you can assume a preset amount of time has passed. In the update function you cache the last state and calculate the new state, in the render function you ...
From the Blue Book (OpenGL Superbible 7th ed., pp. 662f.):
You can have multiple contexts and share data between them, but that isn't very effective. The approach sketched in the other answer (one render thread - mutliple data generation threads) is surely the best practice.
You can have buffer objects to your application's needs and pass pointers around ...