@@ -408,11 +408,19 @@ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $w
408408 // from the rest of the CSS.
409409 $ customCssWithoutComments = preg_replace ('!/\*.*?\*/!s ' , '' , $ customCss );
410410 $ customCssWithoutComments = preg_replace ('!//.*! ' , '' , $ customCssWithoutComments );
411- preg_match_all ('/(@[^{]+{(?:[^{}]*|(?R))*})/ ' , $ customCssWithoutComments , $ atRules );
412- $ atRulesCss = implode ('' , $ atRules [0 ]);
413- $ scopedCss = preg_replace ('/(@[^{]+{(?:[^{}]*|(?R))*})/ ' , '' , $ customCssWithoutComments );
414411
415- $ css = "$ atRulesCss [data-theme- $ themeId] { $ variables $ scopedCss } " ;
412+ // Extract @import rules, because they MUST appear at the very top of the final CSS
413+ // If they remain inside the theme scope or behind normal rules, browsers will ignore them
414+ preg_match_all ('/(@import[^;]+;)/ ' , $ customCssWithoutComments , $ imports );
415+ $ importsCss = implode ('' , $ imports [0 ]);
416+ $ customCssWithoutImports = preg_replace ('/(@import[^;]+;)/ ' , '' , $ customCssWithoutComments );
417+
418+ // Extract all remaining @-rules (e.g. @media), because they cannot be nested inside the theme scope
419+ preg_match_all ('/(@[^{]+{(?:[^{}]*|(?R))*})/ ' , $ customCssWithoutImports , $ atRules );
420+ $ atRulesCss = implode ('' , $ atRules [0 ]);
421+ $ scopedCss = preg_replace ('/(@[^{]+{(?:[^{}]*|(?R))*})/ ' , '' , $ customCssWithoutImports );
422+
423+ $ css = "$ importsCss $ atRulesCss [data-theme- $ themeId] { $ variables $ scopedCss } " ;
416424 }
417425
418426 try {
0 commit comments