wordpress query in header won’t reset and corrupts other loops

Two issues here.

First, you’re not using the loop properly. Instead of the foreach use while ( $query->have_posts() ) { $query->the_post(); //etc.

Secondly, in using foreach($posts as $post) you are overwriting the global $post variable, so if you really must use foreach then use a different variable name!