diff --git a/HellionChat/Ui/TabIconMapping.cs b/HellionChat/Ui/TabIconMapping.cs
new file mode 100644
index 0000000..259dcb4
--- /dev/null
+++ b/HellionChat/Ui/TabIconMapping.cs
@@ -0,0 +1,145 @@
+using Dalamud.Interface;
+
+namespace HellionChat.Ui;
+
+///
+/// Default-Icon-Mapping für Tabs. v1.2.0 Layout-Refresh nutzt das
+/// in Top-Tabs (Icon-Prefix) und Sidebar (Icon-only mit Tooltip).
+/// User können in Settings → Tabs per Tab.Icon-Override eigene
+/// FontAwesome-Glyphen setzen.
+///
+/// Aufteilung:
+/// - +
+/// sind reine String-Logik und stehen aus Test-Sicht ohne
+/// Dalamud-Dependency zur Verfügung (siehe Hilfsklasse
+/// in derselben Datei, die ohne
+/// Dalamud-Imports auskommt).
+/// - liefert den FontAwesomeIcon-Enum-Wert
+/// für Render-Code (T3/T5/T7) und ist daher Dalamud-abhängig.
+///
+internal static class TabIconMapping
+{
+ ///
+ /// FontAwesome-Glyph-Name → Icon-Enum-Lookup. Wird für die
+ /// Production-Resolve-API benötigt. Enthält nur Glyphen aus
+ /// .
+ ///
+ private static readonly Dictionary GlyphLookup = new(StringComparer.OrdinalIgnoreCase)
+ {
+ ["comment"] = FontAwesomeIcon.Comment,
+ ["comments"] = FontAwesomeIcon.Comments,
+ ["cog"] = FontAwesomeIcon.Cog,
+ ["users"] = FontAwesomeIcon.Users,
+ ["user-friends"] = FontAwesomeIcon.UserFriends,
+ ["link"] = FontAwesomeIcon.Link,
+ ["envelope"] = FontAwesomeIcon.Envelope,
+ ["clock"] = FontAwesomeIcon.Clock,
+ ["hashtag"] = FontAwesomeIcon.Hashtag,
+ ["star"] = FontAwesomeIcon.Star,
+ ["heart"] = FontAwesomeIcon.Heart,
+ ["bell"] = FontAwesomeIcon.Bell,
+ ["bookmark"] = FontAwesomeIcon.Bookmark,
+ ["flag"] = FontAwesomeIcon.Flag,
+ ["fire"] = FontAwesomeIcon.Fire,
+ };
+
+ ///
+ /// Picker-Options-Pool — Pass-through zu .
+ ///
+ public static IReadOnlyList PickerOptions => TabIconGlyphResolver.PickerOptions;
+
+ ///
+ /// Pass-through zu .
+ /// Liegt hier nochmal als Convenience-Alias, damit Aufrufer nur
+ /// kennen müssen.
+ ///
+ public static string ResolveGlyphName(Tab tab) => TabIconGlyphResolver.ResolveGlyphName(tab);
+
+ ///
+ /// Production-Surface: liefert das Icon für einen Tab. Wrapper um
+ /// plus
+ /// Enum-Lookup. Wird von Render-Code (T3, T5, T7) verwendet.
+ ///
+ public static FontAwesomeIcon Resolve(Tab tab)
+ {
+ var glyph = TabIconGlyphResolver.ResolveGlyphName(tab);
+ return GlyphLookup.TryGetValue(glyph, out var icon)
+ ? icon
+ : FontAwesomeIcon.Hashtag;
+ }
+}
+
+///
+/// Reine String-Resolver-Logik ohne Dalamud-Dependency. Bewusst
+/// separat, damit Tests (HellionChat.Tests, Microsoft.NET.Sdk ohne
+/// Dalamud-Reference) sie aufrufen können, ohne dass die JIT beim
+/// Methodenaufruf die Dalamud-Assembly laden muss.
+///
+internal static class TabIconGlyphResolver
+{
+ ///
+ /// Glyph-Set, das überhaupt als Override akzeptiert wird. Spiegelt
+ /// die Keys aus .
+ ///
+ private static readonly HashSet KnownGlyphs = new(StringComparer.OrdinalIgnoreCase)
+ {
+ "comment", "comments", "cog", "users", "user-friends", "link",
+ "envelope", "clock", "hashtag", "star", "heart", "bell",
+ "bookmark", "flag", "fire",
+ };
+
+ ///
+ /// Picker-Options-Pool. Wird im Settings-Tab Icon-Combobox angezeigt.
+ /// Reihenfolge ist die UI-Reihenfolge.
+ ///
+ public static readonly IReadOnlyList PickerOptions =
+ ["comment", "comments", "cog", "users", "user-friends", "link",
+ "envelope", "clock", "hashtag", "star", "heart", "bell",
+ "bookmark", "flag", "fire"];
+
+ ///
+ /// Tab-Name → Default-Glyph-Name. Tab.Name wird per Lokalisierung
+ /// gesetzt; wir matchen daher gegen einen Pool aus DE/EN-Synonymen.
+ ///
+ private static readonly Dictionary NameDefaults = new(StringComparer.OrdinalIgnoreCase)
+ {
+ ["allgemein"] = "comment",
+ ["general"] = "comment",
+ ["system"] = "cog",
+ ["free company"] = "users",
+ ["fc"] = "users",
+ ["gruppe"] = "user-friends",
+ ["group"] = "user-friends",
+ ["party"] = "user-friends",
+ ["linkshell"] = "link",
+ ["ls"] = "link",
+ ["cwls"] = "link",
+ ["tells"] = "envelope",
+ ["tell"] = "envelope",
+ };
+
+ ///
+ /// Test-Surface: Glyph-Name-Resolver ohne Dalamud-Dependency.
+ /// Reihenfolge:
+ /// 1. Tab.Icon-Override (falls gesetzt):
+ /// a) bekannter Glyph → diesen Glyph
+ /// b) unbekannter Glyph → harter Fallback "hashtag" (User hat
+ /// bewusst etwas gesetzt, also überstimmt das die Defaults)
+ /// 2. Auto-Tell-Tab → "clock"
+ /// 3. Tab-Name-Default (-Lookup)
+ /// 4. Fallback "hashtag"
+ ///
+ public static string ResolveGlyphName(Tab tab)
+ {
+ if (!string.IsNullOrEmpty(tab.Icon))
+ return KnownGlyphs.Contains(tab.Icon) ? tab.Icon : "hashtag";
+
+ if (tab.IsTempTab)
+ return "clock";
+
+ if (NameDefaults.TryGetValue(tab.Name, out var byName))
+ return byName;
+
+ return "hashtag";
+ }
+}