diff --git a/build.gradle b/build.gradle
index c1c180826a..fb82fdcf88 100644
--- a/build.gradle
+++ b/build.gradle
@@ -130,8 +130,8 @@ dependencies {
     // i'll leave this here commented for easier testing
     //runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69")
     //runtimeOnly fg.deobf("vazkii.quark:Quark:r2.0-212.984")
-    // runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.3-1.6.40")
-    // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.3-3.0.1.24")
+    //runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.103")
+    //runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.0.3.168")
 
     annotationProcessor 'org.spongepowered:mixin:0.8:processor'
 }
diff --git a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java
index 5d545b40ff..7cbb79a56d 100644
--- a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java
+++ b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java
@@ -1,8 +1,8 @@
 package com.simibubi.create.compat.jei;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
@@ -81,12 +81,12 @@ public class CreateJEI implements IModPlugin {
 	}
 
 	public IIngredientManager ingredientManager;
-	final List<CreateRecipeCategory<?>> ALL = new ArrayList<>();
-	final CreateRecipeCategory<?>
+	private final List<CreateRecipeCategory<?>> allCategories = new ArrayList<>();
+	private final CreateRecipeCategory<?>
 
-	milling = register("milling", MillingCategory::new).recipes(AllRecipeTypes.MILLING)
-		.catalyst(AllBlocks.MILLSTONE::get)
-		.build(),
+		milling = register("milling", MillingCategory::new).recipes(AllRecipeTypes.MILLING)
+			.catalyst(AllBlocks.MILLSTONE::get)
+			.build(),
 
 		crushing = register("crushing", CrushingCategory::new).recipes(AllRecipeTypes.CRUSHING)
 			.recipesExcluding(AllRecipeTypes.MILLING::getType, AllRecipeTypes.CRUSHING::getType)
@@ -106,7 +106,9 @@ public class CreateJEI implements IModPlugin {
 			.build(),
 
 		blasting = register("fan_blasting", FanBlastingCategory::new)
-			.recipesExcluding(() -> IRecipeType.SMELTING, () -> IRecipeType.SMOKING)
+			.recipesExcluding(() -> IRecipeType.SMELTING, () -> IRecipeType.BLASTING)
+			.recipes(() -> IRecipeType.BLASTING)
+			.removeRecipes(() -> IRecipeType.SMOKING)
 			.catalystStack(ProcessingViaFanCategory.getFan("fan_blasting"))
 			.build(),
 
@@ -213,20 +215,21 @@ public class CreateJEI implements IModPlugin {
 
 	@Override
 	public void registerCategories(IRecipeCategoryRegistration registration) {
-		ALL.forEach(registration::addRecipeCategories);
+		allCategories.forEach(registration::addRecipeCategories);
 	}
 
 	@Override
 	public void registerRecipes(IRecipeRegistration registration) {
 		ingredientManager = registration.getIngredientManager();
-		ALL.forEach(c -> c.recipes.forEach(s -> registration.addRecipes(s.get(), c.getUid())));
+		allCategories.forEach(c -> c.recipes.forEach(s -> registration.addRecipes(s.get(), c.getUid())));
 	}
 
 	@Override
 	public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
-		ALL.forEach(c -> c.recipeCatalysts.forEach(s -> registration.addRecipeCatalyst(s.get(), c.getUid())));
+		allCategories.forEach(c -> c.recipeCatalysts.forEach(s -> registration.addRecipeCatalyst(s.get(), c.getUid())));
 	}
 
+	@SuppressWarnings({ "unchecked", "rawtypes" })
 	@Override
 	public void registerGuiHandlers(IGuiHandlerRegistration registration) {
 		SlotMover slotMover = new SlotMover();
@@ -239,98 +242,106 @@ public class CreateJEI implements IModPlugin {
 	}
 
 	private class CategoryBuilder<T extends IRecipe<?>> {
-		CreateRecipeCategory<T> category;
+		private CreateRecipeCategory<T> category;
+		private List<Consumer<List<IRecipe<?>>>> recipeListConsumers = new ArrayList<>();
 		private Predicate<CRecipes> pred;
 
-		CategoryBuilder(String name, Supplier<CreateRecipeCategory<T>> category) {
+		public CategoryBuilder(String name, Supplier<CreateRecipeCategory<T>> category) {
 			this.category = category.get();
 			this.category.setCategoryId(name);
-			this.pred = Predicates.alwaysTrue();
+			pred = Predicates.alwaysTrue();
 		}
 
-		CategoryBuilder<T> catalyst(Supplier<IItemProvider> supplier) {
-			return catalystStack(() -> new ItemStack(supplier.get()
-				.asItem()));
-		}
-
-		CategoryBuilder<T> catalystStack(Supplier<ItemStack> supplier) {
-			category.recipeCatalysts.add(supplier);
-			return this;
-		}
-
-		CategoryBuilder<T> recipes(AllRecipeTypes recipeTypeEntry) {
+		public CategoryBuilder<T> recipes(AllRecipeTypes recipeTypeEntry) {
 			return recipes(recipeTypeEntry::getType);
 		}
 
-		CategoryBuilder<T> recipes(Supplier<IRecipeType<T>> recipeType) {
+		public CategoryBuilder<T> recipes(Supplier<IRecipeType<? extends T>> recipeType) {
 			return recipes(r -> r.getType() == recipeType.get());
 		}
 
-		CategoryBuilder<T> recipes(ResourceLocation serializer) {
+		public CategoryBuilder<T> recipes(ResourceLocation serializer) {
 			return recipes(r -> r.getSerializer()
 				.getRegistryName()
 				.equals(serializer));
 		}
 
-		CategoryBuilder<T> recipes(Predicate<IRecipe<?>> pred) {
+		public CategoryBuilder<T> recipes(Predicate<IRecipe<?>> pred) {
 			return recipeList(() -> findRecipes(pred));
 		}
 
-		CategoryBuilder<T> recipes(Predicate<IRecipe<?>> pred, Function<IRecipe<?>, T> converter) {
+		public CategoryBuilder<T> recipes(Predicate<IRecipe<?>> pred, Function<IRecipe<?>, T> converter) {
 			return recipeList(() -> findRecipes(pred), converter);
 		}
 
-		CategoryBuilder<T> recipeList(Supplier<List<? extends IRecipe<?>>> list) {
+		public CategoryBuilder<T> recipeList(Supplier<List<? extends IRecipe<?>>> list) {
 			return recipeList(list, null);
 		}
 
-		CategoryBuilder<T> recipeList(Supplier<List<? extends IRecipe<?>>> list, Function<IRecipe<?>, T> converter) {
-			category.recipes.add(() -> {
-				if (!this.pred.test(AllConfigs.SERVER.recipes))
-					return Collections.emptyList();
+		public CategoryBuilder<T> recipeList(Supplier<List<? extends IRecipe<?>>> list, Function<IRecipe<?>, T> converter) {
+			recipeListConsumers.add(recipes -> {
+				List<? extends IRecipe<?>> toAdd = list.get();
 				if (converter != null)
-					return list.get()
+					toAdd = toAdd
 						.stream()
 						.map(converter)
 						.collect(Collectors.toList());
-				return list.get();
+				recipes.addAll(toAdd);
 			});
 			return this;
 		}
 
-		CategoryBuilder<T> recipesExcluding(Supplier<IRecipeType<? extends T>> recipeType,
+		public CategoryBuilder<T> recipesExcluding(Supplier<IRecipeType<? extends T>> recipeType,
 			Supplier<IRecipeType<? extends T>> excluded) {
-			category.recipes.add(() -> {
-				if (!this.pred.test(AllConfigs.SERVER.recipes))
-					return Collections.emptyList();
-				return findRecipesByTypeExcluding(recipeType.get(), excluded.get());
+			recipeListConsumers.add(recipes -> {
+				recipes.addAll(findRecipesByTypeExcluding(recipeType.get(), excluded.get()));
 			});
 			return this;
 		}
 
-		CategoryBuilder<T> enableWhen(Function<CRecipes, ConfigBool> configValue) {
-			this.pred = c -> configValue.apply(c)
+		public CategoryBuilder<T> removeRecipes(Supplier<IRecipeType<? extends T>> recipeType) {
+			recipeListConsumers.add(recipes -> {
+				removeRecipesByType(recipes, recipeType.get());
+			});
+			return this;
+		}
+
+		public CategoryBuilder<T> catalyst(Supplier<IItemProvider> supplier) {
+			return catalystStack(() -> new ItemStack(supplier.get()
+				.asItem()));
+		}
+
+		public CategoryBuilder<T> catalystStack(Supplier<ItemStack> supplier) {
+			category.recipeCatalysts.add(supplier);
+			return this;
+		}
+
+		public CategoryBuilder<T> enableWhen(Function<CRecipes, ConfigBool> configValue) {
+			pred = c -> configValue.apply(c)
 				.get();
 			return this;
 		}
 
-		CategoryBuilder<T> enableWhenBool(Function<CRecipes, Boolean> configValue) {
-			this.pred = configValue::apply;
+		public CategoryBuilder<T> enableWhenBool(Function<CRecipes, Boolean> configValue) {
+			pred = configValue::apply;
 			return this;
 		}
 
-		CreateRecipeCategory<T> build() {
-			ALL.add(category);
+		public CreateRecipeCategory<T> build() {
+			if (pred.test(AllConfigs.SERVER.recipes))
+				category.recipes.add(() -> {
+					List<IRecipe<?>> recipes = new ArrayList<>();
+					for (Consumer<List<IRecipe<?>>> consumer : recipeListConsumers)
+						consumer.accept(recipes);
+					return recipes;
+				});
+			allCategories.add(category);
 			return category;
 		}
 
 	}
 
-	static List<IRecipe<?>> findRecipesByType(IRecipeType<?> type) {
-		return findRecipes(r -> r.getType() == type);
-	}
-
-	static List<IRecipe<?>> findRecipes(Predicate<IRecipe<?>> predicate) {
+	public static List<IRecipe<?>> findRecipes(Predicate<IRecipe<?>> predicate) {
 		return Minecraft.getInstance().world.getRecipeManager()
 			.getRecipes()
 			.stream()
@@ -338,24 +349,44 @@ public class CreateJEI implements IModPlugin {
 			.collect(Collectors.toList());
 	}
 
-	static List<IRecipe<?>> findRecipesByTypeExcluding(IRecipeType<?> type, IRecipeType<?> excludingType) {
-		List<IRecipe<?>> byType = findRecipes(r -> r.getType() == type);
-		List<IRecipe<?>> byExcludingType = findRecipes(r -> r.getType() == excludingType);
-		byType.removeIf(recipe -> {
-			for (IRecipe<?> r : byExcludingType) {
-				ItemStack[] matchingStacks = recipe.getIngredients()
-					.get(0)
-					.getMatchingStacks();
-				if (matchingStacks.length == 0)
-					return true;
-				if (r.getIngredients()
-					.get(0)
-					.test(matchingStacks[0]))
-					return true;
-			}
-			return false;
-		});
+	public static List<IRecipe<?>> findRecipesByType(IRecipeType<?> type) {
+		return findRecipes(recipe -> recipe.getType() == type);
+	}
+
+	public static List<IRecipe<?>> findRecipesByTypeExcluding(IRecipeType<?> type, IRecipeType<?> excludingType) {
+		List<IRecipe<?>> byType = findRecipesByType(type);
+		removeRecipesByType(byType, excludingType);
 		return byType;
 	}
 
+	public static List<IRecipe<?>> findRecipesByTypeExcluding(IRecipeType<?> type, IRecipeType<?>... excludingTypes) {
+		List<IRecipe<?>> byType = findRecipesByType(type);
+		for (IRecipeType<?> excludingType : excludingTypes)
+			removeRecipesByType(byType, excludingType);
+		return byType;
+	}
+
+	public static void removeRecipesByType(List<IRecipe<?>> recipes, IRecipeType<?> type) {
+		List<IRecipe<?>> byType = findRecipesByType(type);
+		recipes.removeIf(recipe -> {
+			for (IRecipe<?> r : byType)
+				if (doInputsMatch(recipe, r))
+					return true;
+			return false;
+		});
+	}
+
+	public static boolean doInputsMatch(IRecipe<?> recipe1, IRecipe<?> recipe2) {
+		ItemStack[] matchingStacks = recipe1.getIngredients()
+			.get(0)
+			.getMatchingStacks();
+		if (matchingStacks.length == 0)
+			return true;
+		if (recipe2.getIngredients()
+			.get(0)
+			.test(matchingStacks[0]))
+			return true;
+		return false;
+	}
+
 }
diff --git a/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java
index 84543da40a..55bfbdab24 100644
--- a/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java
+++ b/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java
@@ -31,13 +31,13 @@ import net.minecraftforge.fluids.FluidStack;
 
 public abstract class CreateRecipeCategory<T extends IRecipe<?>> implements IRecipeCategory<T> {
 
-	public List<Supplier<? extends Object>> recipeCatalysts = new ArrayList<>();
-	public List<Supplier<List<? extends IRecipe<?>>>> recipes = new ArrayList<>();
-	public ResourceLocation uid;
+	public final List<Supplier<List<? extends IRecipe<?>>>> recipes = new ArrayList<>();
+	public final List<Supplier<? extends Object>> recipeCatalysts = new ArrayList<>();
 
+	protected ResourceLocation uid;
 	protected String name;
-	private IDrawable icon;
 	private IDrawable background;
+	private IDrawable icon;
 
 	public CreateRecipeCategory(IDrawable icon, IDrawable background) {
 		this.background = background;
@@ -49,11 +49,6 @@ public abstract class CreateRecipeCategory<T extends IRecipe<?>> implements IRec
 		this.name = name;
 	}
 
-	@Override
-	public IDrawable getIcon() {
-		return icon;
-	}
-
 	@Override
 	public ResourceLocation getUid() {
 		return uid;
@@ -70,6 +65,11 @@ public abstract class CreateRecipeCategory<T extends IRecipe<?>> implements IRec
 		return background;
 	}
 
+	@Override
+	public IDrawable getIcon() {
+		return icon;
+	}
+
 	protected static AllGuiTextures getRenderedSlot(IRecipe<?> recipe, int index) {
 		AllGuiTextures jeiSlot = AllGuiTextures.JEI_SLOT;
 		if (!(recipe instanceof ProcessingRecipe))
diff --git a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java
index 2f03d20569..69b2292d82 100644
--- a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java
+++ b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java
@@ -21,7 +21,6 @@ import mezz.jei.api.ingredients.IIngredients;
 import net.minecraft.item.ItemStack;
 import net.minecraft.item.crafting.IRecipe;
 import net.minecraft.util.math.vector.Vector3f;
-import net.minecraft.util.text.TextFormatting;
 
 public abstract class ProcessingViaFanCategory<T extends IRecipe<?>> extends CreateRecipeCategory<T> {
 
@@ -41,7 +40,7 @@ public abstract class ProcessingViaFanCategory<T extends IRecipe<?>> extends Cre
 
 	public static Supplier<ItemStack> getFan(String name) {
 		return () -> AllBlocks.ENCASED_FAN.asStack()
-			.setDisplayName(Lang.translate("recipe." + name + ".fan").formatted(TextFormatting.RESET));
+			.setDisplayName(Lang.translate("recipe." + name + ".fan").styled(style -> style.withItalic(false)));
 	}
 
 	@Override