diff --git a/Generation/Converters/Argumentum.AssetConverter.Tests/MindmapGeneration/VirtuesMindmapWrapperLocalizationTests.cs b/Generation/Converters/Argumentum.AssetConverter.Tests/MindmapGeneration/VirtuesMindmapWrapperLocalizationTests.cs
new file mode 100644
index 00000000..7f487ede
--- /dev/null
+++ b/Generation/Converters/Argumentum.AssetConverter.Tests/MindmapGeneration/VirtuesMindmapWrapperLocalizationTests.cs
@@ -0,0 +1,161 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Argumentum.AssetConverter.Mindmapper;
+using Xunit;
+
+namespace Argumentum.AssetConverter.Tests.MindmapGeneration
+{
+ ///
+ /// Regression guard for issue #725: the Virtues mind-map HTML wrappers
+ /// (Argumentation_Virtues_{lang}.html) must inline the **localized**
+ /// Argumentum_Virtues_MindMap_{lang}.content.svg per language — not the
+ /// French source SVG. The pipeline path is
+ /// VirtueMindMapDocumentConfig.GenerateHtmlSvgWrappers →
+ /// , which substitutes the
+ /// post-localization content.svg into the [SVGCONTENT] placeholder.
+ ///
+ /// The **committed** wrappers are stale (generated 2026-05-24 by the pre-#665
+ /// code, when the Virtues content.svg was FR-frozen — see
+ /// docs/investigations/2026-06-25-virtues-mindmap-fr-frozen-mechanism.md).
+ /// They were skipped by every later SVG regen because
+ /// AssetConverterConfig.OverwriteExistingHtmlMaps defaults to false
+ /// while OverwriteExistingDocs is true. The stale files are tracked
+ /// separately for a post-tag regen (po-2023 lane); this test does NOT touch
+ /// Cards/.
+ ///
+ /// What this test pins is the **assembly contract**: feeding the *already-localized*
+ /// committed content.svg through
+ /// must yield a wrapper whose visible node text matches the target language. It
+ /// mirrors the Fallacies Playwright suite
+ /// (VisualTests/MindmapWrapperTests.cs) but runs headless in CI (no browser),
+ /// so a future regression in the helper or in the SVG-localization wiring surfaces
+ /// here without RDP/FreeMind.
+ ///
+ public class VirtuesMindmapWrapperLocalizationTests
+ {
+ ///
+ /// Visible node text that is French-only in the FR-frozen Virtues mind map.
+ /// Empirically (master 6ce91ef8) present 27× in the FR content.svg
+ /// and 0× in every localized one — a sharp cross-contamination discriminator.
+ ///
+ private const string FrenchFrozenMarker = "Honnêteté intellectuelle";
+
+ private static readonly string RepoRoot =
+ Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", ".."));
+
+ private static readonly string IncludedTemplatePath =
+ Path.Combine(RepoRoot, "Cards", "Fallacies", "Mindmaps", "included.html");
+
+ private static string GetVirtuesContentSvgPath(string lang)
+ => Path.Combine(RepoRoot, "Cards", "Fallacies", "Mindmaps", lang,
+ $"Argumentum_Virtues_MindMap_{lang}.content.svg");
+
+ private static int CountInRange(string s, char low, char high)
+ {
+ var n = 0;
+ foreach (var c in s)
+ if (c >= low && c <= high) n++;
+ return n;
+ }
+
+ private static int CountCyrillic(string s) => CountInRange(s, 'Ѐ', 'ӿ');
+ private static int CountCjk(string s) => CountInRange(s, '一', '鿿');
+ private static int CountArabicScript(string s) => CountInRange(s, '', 'ۿ');
+
+ ///
+ /// For each language, the wrapper assembled from the committed localized
+ /// content.svg must carry that language's script/labels and must NOT
+ /// carry the French-frozen marker. This is the headless proof that the correct
+ /// per-language content.svg is the one being inlined.
+ ///
+ [Theory]
+ [InlineData("fr")]
+ [InlineData("en")]
+ [InlineData("ru")]
+ [InlineData("zh")]
+ [InlineData("ar")]
+ [InlineData("fa")]
+ public async Task FormatWrapper_WithLocalizedVirtuesContentSvg_WrapperMatchesTargetLanguage(string lang)
+ {
+ Assert.True(File.Exists(IncludedTemplatePath),
+ $"Missing included.html template: {IncludedTemplatePath}");
+ var svgPath = GetVirtuesContentSvgPath(lang);
+ Assert.True(File.Exists(svgPath),
+ $"Missing localized Virtues content.svg fixture: {svgPath}. " +
+ "If this was deleted, the test fixture must be regenerated (see issue #725).");
+
+ var template = await File.ReadAllTextAsync(IncludedTemplatePath);
+ var svg = await File.ReadAllTextAsync(svgPath);
+
+ var wrapper = MindMapHtmlWrapper.FormatWrapper(
+ template,
+ svgRelativePath: $"Argumentum_Virtues_MindMap_{lang}.content.svg",
+ svgContent: svg);
+
+ // The two placeholder tokens must both be consumed (no partial substitution).
+ Assert.DoesNotContain("[SVGCONTENT]", wrapper);
+ Assert.DoesNotContain("[SVGPATH]", wrapper);
+ // The inlined SVG body must be present.
+ Assert.Contains("