-- =========================================================================
-- FILE: Settings.lua (TBC)
-- Ported from Retail with Raider.IO / M+ / AXIOM Inspection removed
-- =========================================================================
local addonName, NS = ...

local GR = _G["GRS_MainFrame"] or NS.GR

if not GR then
    print("|cffff0000A.X.I.O.M. Error:|r Main Frame not found in Settings.lua")
    return
end

-- ... [Visual Helpers] ...
local function SafeCreateBg(f, r, g, b, a) if not f then return end; if f.bg then f.bg:SetColorTexture(r, g, b, a) else local t = f:CreateTexture(nil, "BORDER"); t:SetAllPoints(); t:SetColorTexture(r, g, b, a); f.bg = t end end
local function SafeCreateBorder(f, r, g, b, a) if not f then return end; if f.border then f.border:SetColorTexture(r, g, b, a) else local border = f:CreateTexture(nil, "BACKGROUND"); border:SetPoint("TOPLEFT", -1, 1); border:SetPoint("BOTTOMRIGHT", 1, -1); border:SetColorTexture(r, g, b, a); f.border = border end end
local function SafeSkinButton(btn) if not btn then return end; btn:SetNormalTexture(""); btn:SetHighlightTexture(""); btn:SetPushedTexture(""); btn:SetDisabledTexture(""); if btn.Left then btn.Left:SetAlpha(0) end; if btn.Middle then btn.Middle:SetAlpha(0) end; if btn.Right then btn.Right:SetAlpha(0) end; SafeCreateBg(btn, 0, 0, 0, 1); SafeCreateBorder(btn, 0, 0, 0, 1); if btn.GetFontString and btn:GetFontString() then btn:GetFontString():SetTextColor(1, 1, 1) end; btn:HookScript("OnEnter", function(s) if s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 1) end end); btn:HookScript("OnLeave", function(s) if s.bg then s.bg:SetColorTexture(0, 0, 0, 1) end end) end
local function CreateColorSlider(parent, label, getVal, setVal) local s = CreateFrame("Slider", nil, parent, "OptionsSliderTemplate"); s:SetWidth(180); s:SetHeight(15); s:SetMinMaxValues(0, 1); s:SetValueStep(0.01); s:SetObeyStepOnDrag(true); local txt = s:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); txt:SetPoint("BOTTOMLEFT", s, "TOPLEFT", 0, 2); txt:SetText(label); local val = s:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); val:SetPoint("BOTTOMRIGHT", s, "TOPRIGHT", 0, 2); local n = s:GetName(); if n then if _G[n.."Low"] then _G[n.."Low"]:SetText("") end; if _G[n.."High"] then _G[n.."High"]:SetText("") end; if _G[n.."Text"] then _G[n.."Text"]:SetText("") end end; local initialVal = 0; if getVal then initialVal = getVal() or 0 end; s:SetValue(initialVal); val:SetText(string.format("%.2f", initialVal)); s:SetScript("OnValueChanged", function(self, v) v = math.floor(v * 100 + 0.5) / 100; val:SetText(string.format("%.2f", v)); if setVal then setVal(v) end end); return s end

-- =========================================================================
-- GUILD IMPORT CONSTANTS (TBC - M+ Score removed)
-- =========================================================================

GR.GUILD_IMPORT_FIELDS = {
    { key = "Name", label = "Name", idx = 1 },
    { key = "Rank", label = "Rank", idx = 2 },
    { key = "Level", label = "Level", idx = 3 },
    { key = "Class", label = "Class", idx = 4 },
    { key = "Race", label = "Race", idx = 5 },
    { key = "Sex", label = "Sex", idx = 6 },
    { key = "LastOnline", label = "Last Online (Days)", idx = 7 },
    { key = "MainAlt", label = "Main/Alt", idx = 8 },
    { key = "Alts", label = "Player Alts", idx = 9 },
    { key = "JoinDate", label = "Join Date", idx = 10 },
    { key = "PromoDate", label = "Promo Date", idx = 11 },
    { key = "RankHist", label = "Rank History", idx = 12 },
    { key = "Birthday", label = "Birthday", idx = 13 },
    { key = "Rep", label = "Guild Rep", idx = 14 },
    { key = "PubNote", label = "Public Note", idx = 15 },
    { key = "OffNote", label = "Officer Note", idx = 16 },
    { key = "CustNote", label = "Custom Note", idx = 17 },
    -- M+ Score removed for TBC
    { key = "Faction", label = "Faction", idx = 19 },
    { key = "GUID", label = "Player GUID", idx = 20 },
}

local SHORT_MONTHS = { Jan="January", Feb="February", Mar="March", Apr="April", May="May", Jun="June", Jul="July", Aug="August", Sep="September", Oct="October", Nov="November", Dec="December" }
local INV_MONTHS = {}; for k,v in pairs(SHORT_MONTHS) do INV_MONTHS[v] = k end

local function ParseImportDate(dateStr)
    if not dateStr or dateStr == "" then return nil, nil end
    local d, m = string.match(dateStr, "^(%d+)%s+(%a+)")
    if d and m then local fullMonth = SHORT_MONTHS[m] or m; return fullMonth, d end
    return nil, nil
end

local function FormatImportDate(d, m, y)
    if not d or not m then return "" end
    local shortM = string.sub(m, 1, 3); if INV_MONTHS[m] then shortM = INV_MONTHS[m] end
    local yStr = y or date("%y"); return string.format("%s %s '%s", d, shortM, yStr)
end

-- =========================================================================
-- 1. SETTINGS VIEW BUILDER
-- =========================================================================

function GR:BuildSettingsView()
    if not self.db then self.db = {} end
    if not self.db.theme then self.db.theme = {} end
    local d = self.db.theme
    if not d.header then d.header = {r=0.1, g=0.1, b=0.2, a=1} end
    if not d.background then d.background = {r=0.05, g=0.05, b=0.05, a=0.95} end
    if not d.buttons then d.buttons = {r=0.2, g=0.2, b=0.2, a=1} end

    local parent = CreateFrame("Frame", "GRS_SettingsView", self.ViewContainer); parent:SetAllPoints(); parent:Hide(); self.views[7] = parent
    
    -- Horizontal Scrollbar Factory (matches RaidRoster style)
    local function CreateHorizontalScrollbar(parentFrame, targetScrollFrame)
        local container = CreateFrame("Frame", nil, parentFrame, "BackdropTemplate")
        container:SetHeight(18)
        container:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = false, tileSize = 16, edgeSize = 12, insets = { left = 3, right = 3, top = 3, bottom = 3 } })
        container:SetBackdropColor(0, 0, 0, 0.8)
        container:SetBackdropBorderColor(0.6, 0.6, 0.6, 1)
        container:SetFrameLevel(parentFrame:GetFrameLevel() + 10)
        
        local leftBtn = CreateFrame("Button", nil, container)
        leftBtn:SetSize(16, 16); leftBtn:SetPoint("LEFT", 2, 0)
        leftBtn:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up")
        leftBtn:GetNormalTexture():SetRotation(math.rad(90))
        leftBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight")
        
        local rightBtn = CreateFrame("Button", nil, container)
        rightBtn:SetSize(16, 16); rightBtn:SetPoint("RIGHT", -2, 0)
        rightBtn:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up")
        rightBtn:GetNormalTexture():SetRotation(math.rad(90))
        rightBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight")
        
        local slider = CreateFrame("Slider", nil, container)
        slider:SetOrientation("HORIZONTAL")
        slider:SetPoint("LEFT", leftBtn, "RIGHT", 0, 0)
        slider:SetPoint("RIGHT", rightBtn, "LEFT", 0, 0)
        slider:SetHeight(18)
        local track = slider:CreateTexture(nil, "BACKGROUND"); track:SetAllPoints(); track:SetColorTexture(0.1, 0.1, 0.1, 1)
        local thumb = slider:CreateTexture(nil, "ARTWORK"); thumb:SetSize(24, 14); thumb:SetColorTexture(0.5, 0.5, 0.5, 1)
        slider:SetThumbTexture(thumb)
        
        local step = 40
        leftBtn:SetScript("OnClick", function() slider:SetValue(slider:GetValue() - step) end)
        rightBtn:SetScript("OnClick", function() slider:SetValue(slider:GetValue() + step) end)
        slider:SetScript("OnValueChanged", function(self, value) targetScrollFrame:SetHorizontalScroll(value); thumb:SetColorTexture(0.8, 0.6, 0, 1) end)
        slider:SetScript("OnMouseUp", function() thumb:SetColorTexture(0.5, 0.5, 0.5, 1) end)
        
        container.SetMinMaxValues = function(self, min, max) slider:SetMinMaxValues(min, max); if max <= min then leftBtn:Disable(); rightBtn:Disable(); thumb:Hide(); container:Hide() else leftBtn:Enable(); rightBtn:Enable(); thumb:Show(); container:Show() end end
        container.GetValue = function(self) return slider:GetValue() end
        container.SetValue = function(self, v) slider:SetValue(v) end
        container.slider = slider
        return container
    end
    
    -- Create scroll frame for horizontal scrolling
    local scrollFrame = CreateFrame("ScrollFrame", "GRS_SettingsScroll", parent)
    scrollFrame:SetPoint("TOPLEFT", 0, -75) -- Offset 75px from top
    scrollFrame:SetPoint("BOTTOMRIGHT", 0, 20) -- Leave room for horizontal scrollbar
    
    local canvas = CreateFrame("Frame", nil, scrollFrame)
    canvas:SetSize(1500, 600) -- Fixed width to accommodate all panes
    scrollFrame:SetScrollChild(canvas)
    SafeCreateBg(canvas, 0.1, 0.1, 0.1, 1)
    self.SettingsCanvas = canvas
    
    -- Horizontal scrollbar
    local hScrollbar = CreateHorizontalScrollbar(parent, scrollFrame)
    hScrollbar:SetPoint("BOTTOMLEFT", 15, 5)
    hScrollbar:SetPoint("BOTTOMRIGHT", -15, 5)
    hScrollbar:SetMinMaxValues(0, 0) -- Will be updated on size change
    
    -- Update scroll range when parent resizes
    parent:SetScript("OnSizeChanged", function(self, w, h)
        local canvasWidth = canvas:GetWidth()
        local viewWidth = scrollFrame:GetWidth()
        local maxScroll = math.max(0, canvasWidth - viewWidth)
        hScrollbar:SetMinMaxValues(0, maxScroll)
    end)
    
    -- Mouse wheel horizontal scroll (with shift key)
    scrollFrame:EnableMouseWheel(true)
    scrollFrame:SetScript("OnMouseWheel", function(self, delta)
        if IsShiftKeyDown() then
            local cur = hScrollbar:GetValue()
            hScrollbar:SetValue(cur - (delta * 40))
        end
    end)
    
    local function UpdateLiveTheme() GR:ApplyTheme(nil) end

    -- LEFT PANE (reduced from 500 to 420)
    local paneLeft = CreateFrame("Frame", nil, canvas); paneLeft:SetPoint("TOPLEFT", 15, -50); paneLeft:SetPoint("BOTTOMLEFT", 15, 30); paneLeft:SetWidth(420)
    SafeCreateBorder(paneLeft, 0.3, 0.3, 0.3, 1); SafeCreateBg(paneLeft, 0.08, 0.08, 0.08, 0.5)
    local hdrLeft = paneLeft:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hdrLeft:SetPoint("TOPLEFT", 15, -15); hdrLeft:SetText(NS.L["GENERAL_SETTINGS"] or "General Settings")
    
    local lblScale = paneLeft:CreateFontString(nil, "OVERLAY", "GameFontNormal"); lblScale:SetPoint("TOPLEFT", 20, -60); lblScale:SetText(NS.L["UI_SCALE"] or "UI Scale")
    local valScale = paneLeft:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); valScale:SetPoint("LEFT", lblScale, "RIGHT", 10, 0); valScale:SetText(string.format("%.2f", self.db.scale or 1.0))
    local sliderScale = CreateFrame("Slider", "GRS_ScaleSlider", paneLeft, "OptionsSliderTemplate"); sliderScale:SetPoint("TOPLEFT", 20, -85); sliderScale:SetWidth(380); sliderScale:SetMinMaxValues(0.6, 1.4); sliderScale:SetValueStep(0.05); sliderScale:SetObeyStepOnDrag(true)
    local sName = sliderScale:GetName(); if _G[sName.."Low"] then _G[sName.."Low"]:SetText("") end; if _G[sName.."High"] then _G[sName.."High"]:SetText("") end; if _G[sName.."Text"] then _G[sName.."Text"]:SetText("") end
    sliderScale:SetValue(self.db.scale or 1.0)
    sliderScale:SetScript("OnValueChanged", function(s, val) local v = math.floor(val * 100 + 0.5) / 100; valScale:SetText(string.format("%.2f", v)) end)
    sliderScale:SetScript("OnMouseUp", function(s) local v = math.floor(s:GetValue() * 100 + 0.5) / 100; if GR.db then GR.db.scale = v end; GR:SetScale(v) end)

    local chkCompact = CreateFrame("CheckButton", "GRS_Settings_CompactCheck", paneLeft, "UICheckButtonTemplate"); chkCompact:SetSize(24, 24); chkCompact:SetPoint("TOPLEFT", 20, -125)
    chkCompact.text = chkCompact:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); chkCompact.text:SetPoint("LEFT", chkCompact, "RIGHT", 5, 0); chkCompact.text:SetText(NS.L["COMPACT_MODE"] or "Enable Compact mode"); chkCompact:SetChecked(self.db.compactMode or false)

    local chkBypass = CreateFrame("CheckButton", "GRS_Settings_BypassCheck", paneLeft, "UICheckButtonTemplate"); chkBypass:SetSize(24, 24); chkBypass:SetPoint("TOPLEFT", 20, -155)
    chkBypass.text = chkBypass:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); chkBypass.text:SetPoint("LEFT", chkBypass, "RIGHT", 5, 0); chkBypass.text:SetText(NS.L["BYPASS_FILTER"] or "Bypass class rotation filter"); chkBypass:SetChecked(self.db.bypassFilter or false)

    local btnApplySettings = CreateFrame("Button", nil, paneLeft, "UIPanelButtonTemplate"); btnApplySettings:SetSize(120, 30); btnApplySettings:SetPoint("TOPLEFT", 20, -190); btnApplySettings:SetText(NS.L["APPLY"] or "Apply"); SafeSkinButton(btnApplySettings)
    btnApplySettings:SetScript("OnClick", function() GR.db.compactMode = chkCompact:GetChecked(); GR.db.bypassFilter = chkBypass:GetChecked(); if GR.ToggleCompactMode then GR:ToggleCompactMode(GR.db.compactMode) end; print("|cff00ff00A.X.I.O.M.:|r " .. (NS.L["SETTINGS_APPLIED"] or "Settings Applied.")) end)

    local txtReload = paneLeft:CreateFontString(nil, "OVERLAY", "GameFontRedSmall"); txtReload:SetPoint("BOTTOMLEFT", 20, 50); txtReload:SetText(NS.L["RELOAD_UI_NOTE"] or "Reload UI for scale/theme changes")
    local btnReload = CreateFrame("Button", nil, paneLeft, "UIPanelButtonTemplate"); btnReload:SetSize(120, 30); btnReload:SetPoint("BOTTOMLEFT", 20, 15); btnReload:SetText(NS.L["RELOAD_UI"] or "Reload UI"); btnReload:SetScript("OnClick", function() ReloadUI() end); SafeSkinButton(btnReload)

    -- MID PANE
    local paneMid = CreateFrame("Frame", nil, canvas); paneMid:SetPoint("TOPLEFT", paneLeft, "TOPRIGHT", 0, 0); paneMid:SetPoint("BOTTOMLEFT", paneLeft, "BOTTOMRIGHT", 0, 0); paneMid:SetWidth(250); SafeCreateBorder(paneMid, 0.3, 0.3, 0.3, 1)
    local function CreateSubPane(relPoint, yOff, title, desc)
        local f = CreateFrame("Frame", nil, paneMid); if relPoint then f:SetPoint("TOPLEFT", relPoint, "BOTTOMLEFT", 0, yOff); f:SetPoint("TOPRIGHT", relPoint, "BOTTOMRIGHT", 0, yOff) else f:SetPoint("TOPLEFT", 0, 0); f:SetPoint("TOPRIGHT", 0, 0) end
        f:SetHeight((canvas:GetHeight() - 80) / 3); SafeCreateBorder(f, 0.2, 0.2, 0.2, 1)
        local t = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); t:SetPoint("TOP", 0, -10); t:SetText(title)
        if desc then local d = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); d:SetPoint("TOPLEFT", 10, -30); d:SetWidth(230); d:SetJustifyH("LEFT"); d:SetText(desc) end
        return f
    end
    local function MakeColorControls(parent, yStart, dbKey, useAlpha)
        local function GetCol(k) local t = GR.db.theme[dbKey]; return t and t[k] or (k == "a" and 1 or 0) end
        local function SetCol(k, v) if GR.db.theme[dbKey] then GR.db.theme[dbKey][k] = v; UpdateLiveTheme() end end
        local rS = CreateColorSlider(parent, "Red", function() return GetCol("r") end, function(v) SetCol("r", v) end); rS:SetPoint("TOP", 0, yStart)
        local gS = CreateColorSlider(parent, "Green", function() return GetCol("g") end, function(v) SetCol("g", v) end); gS:SetPoint("TOP", 0, yStart - 35)
        local bS = CreateColorSlider(parent, "Blue", function() return GetCol("b") end, function(v) SetCol("b", v) end); bS:SetPoint("TOP", 0, yStart - 70)
        if useAlpha then local aS = CreateColorSlider(parent, "Alpha", function() return GetCol("a") end, function(v) SetCol("a", v) end); aS:SetPoint("TOP", 0, yStart - 105)
        else if GR.db.theme[dbKey] then GR.db.theme[dbKey].a = 1 end end
    end
    local subTop = CreateSubPane(nil, 0, NS.L["HEADER_SIDEBAR"] or "Header / Sidebar", NS.L["TITLE_SIDEBAR_COLORS"] or "Title Bar & Sidebar Colors"); MakeColorControls(subTop, -50, "header", false)
    local subMid = CreateSubPane(subTop, 0, NS.L["BACKGROUND_PANE"] or "Background Pane", nil); MakeColorControls(subMid, -40, "background", true)
    local subBot = CreateSubPane(subMid, 0, NS.L["BUTTONS_TEXT"] or "Buttons & Text", nil); MakeColorControls(subBot, -40, "buttons", false)

    -- RIGHT PANE
    local paneRight = CreateFrame("Frame", nil, canvas); paneRight:SetPoint("TOPLEFT", paneMid, "TOPRIGHT", 0, 0); paneRight:SetPoint("BOTTOMLEFT", paneMid, "BOTTOMRIGHT", 0, 0); paneRight:SetWidth(300); SafeCreateBorder(paneRight, 0.3, 0.3, 0.3, 1); SafeCreateBg(paneRight, 0.05, 0.05, 0.05, 0.5)
    local hdrRight = paneRight:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hdrRight:SetPoint("TOPLEFT", 15, -15); hdrRight:SetText(NS.L["ADVANCED_TOOLS"] or "Advanced Tools")
    
    local chkMacro = CreateFrame("CheckButton", "GRS_Settings_MacroCheck", paneRight, "UICheckButtonTemplate"); chkMacro:SetSize(24, 24); chkMacro:SetPoint("TOPLEFT", 20, -50)
    chkMacro.text = chkMacro:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); chkMacro.text:SetPoint("LEFT", chkMacro, "RIGHT", 5, 0); chkMacro.text:SetText(NS.L["ENABLE_MACRO_TOOLS"] or "Enable Macro Tools")
    if DB_Rmap_Tools and DB_Rmap_Tools.settings then chkMacro:SetChecked(DB_Rmap_Tools.settings.isMacroPanelOpen) else chkMacro:SetChecked(false) end
    chkMacro:SetScript("OnClick", function(self)
        local isEnabled = self:GetChecked(); if DB_Rmap_Tools then if not DB_Rmap_Tools.settings then DB_Rmap_Tools.settings = {} end; DB_Rmap_Tools.settings.isMacroPanelOpen = isEnabled end
        if isEnabled then if GR.InitMacroDashboard then GR:InitMacroDashboard() end; if GR.MacroPanel then GR.MacroPanel:Show() end else if GR.MacroPanel then GR.MacroPanel:Hide() end end
    end)

    local chkSocial = CreateFrame("CheckButton", "GRS_Settings_SocialCheck", paneRight, "UICheckButtonTemplate"); chkSocial:SetSize(24, 24); chkSocial:SetPoint("TOPLEFT", 20, -110)
    chkSocial.text = chkSocial:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); chkSocial.text:SetPoint("LEFT", chkSocial, "RIGHT", 5, 0); chkSocial.text:SetText(NS.L["SOCIAL_GUILD_ACTIVITIES"] or "Social Guild Activities"); chkSocial:SetChecked(self.db.socialEnabled or false)
    chkSocial:SetScript("OnClick", function(self) GR.db.socialEnabled = self:GetChecked(); print("|cff00ff00A.X.I.O.M.:|r Social Activities " .. (GR.db.socialEnabled and "Enabled" or "Disabled")); if GR.UpdateRosterList then GR:UpdateRosterList() end end)
    local noteSocial = paneRight:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); noteSocial:SetPoint("TOPLEFT", 20, -140); noteSocial:SetWidth(260); noteSocial:SetJustifyH("LEFT"); noteSocial:SetText(NS.L["SOCIAL_NOTE"] or "Enables birthdates, anniversaries, and custom social notes for guild members."); noteSocial:SetTextColor(0.6, 0.6, 0.6)

    -- [[ AXIOM INSPECTION / M+ ROSTER TOGGLES REMOVED FOR TBC ]]

    -- [[ IMPORT / EXPORT BUTTONS - at bottom of pane ]]
    local btnImportGRM = CreateFrame("Button", nil, paneRight, "UIPanelButtonTemplate"); btnImportGRM:SetSize(260, 25); btnImportGRM:SetPoint("BOTTOM", 0, 50); btnImportGRM:SetText(NS.L["IMPORT_FROM_GRM"] or "Import from GRM"); SafeSkinButton(btnImportGRM)
    btnImportGRM:SetScript("OnClick", function() GR:OpenGuildImportPopup("IMPORT") end)

    local btnExportGRM = CreateFrame("Button", nil, paneRight, "UIPanelButtonTemplate"); btnExportGRM:SetSize(260, 25); btnExportGRM:SetPoint("TOP", btnImportGRM, "BOTTOM", 0, -10); btnExportGRM:SetText("Export to GRM"); SafeSkinButton(btnExportGRM)
    btnExportGRM:SetScript("OnClick", function() GR:OpenGuildImportPopup("EXPORT") end)

    -- CUSTOM BG PANE (Fixed width to allow Language pane)
    local paneCustom = CreateFrame("Frame", nil, canvas); paneCustom:SetPoint("TOPLEFT", paneRight, "TOPRIGHT", 0, 0); paneCustom:SetPoint("BOTTOMLEFT", paneRight, "BOTTOMRIGHT", 0, 0); paneCustom:SetWidth(200); SafeCreateBorder(paneCustom, 0.3, 0.3, 0.3, 1); SafeCreateBg(paneCustom, 0.05, 0.05, 0.05, 0.5)
    local hdrCustom = paneCustom:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hdrCustom:SetPoint("TOPLEFT", 10, -15); hdrCustom:SetText(NS.L["CUSTOM_BACKGROUND"] or "Custom Background")
    local chkEnableBg = CreateFrame("CheckButton", nil, paneCustom, "UICheckButtonTemplate"); chkEnableBg:SetSize(24, 24); chkEnableBg:SetPoint("TOPLEFT", 10, -40)
    chkEnableBg.text = chkEnableBg:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); chkEnableBg.text:SetPoint("LEFT", chkEnableBg, "RIGHT", 5, 0); chkEnableBg.text:SetText(NS.L["ENABLE_CUSTOM_BG"] or "Enable Custom Background")
    if not self.db.customBackgrounds then self.db.customBackgrounds = {} end; chkEnableBg:SetChecked(self.db.customBackgrounds.enabled or false)
    local lblDir = paneCustom:CreateFontString(nil, "OVERLAY", "GameFontNormal"); lblDir:SetPoint("TOPLEFT", 10, -125); lblDir:SetText(NS.L["SET_DIRECTORY"] or "Set directory")
    local edtDir = CreateFrame("EditBox", nil, paneCustom, "InputBoxTemplate"); edtDir:SetSize(140, 20); edtDir:SetPoint("TOPLEFT", 10, -145); edtDir:SetAutoFocus(false); edtDir:SetFontObject("ChatFontSmall"); edtDir:SetText(self.db.customBackgrounds.directory or "Interface\\AddOns\\GuildRecruiterManagement\\Media")
    local btnDir = CreateFrame("Button", nil, paneCustom, "UIPanelButtonTemplate"); btnDir:SetSize(40, 20); btnDir:SetPoint("LEFT", edtDir, "RIGHT", 5, 0); btnDir:SetText("Set"); SafeCreateBg(btnDir, 0, 0, 0, 1); SafeCreateBorder(btnDir, 0.3, 0.3, 0.3, 1)
    btnDir:SetScript("OnClick", function() GR.db.customBackgrounds.directory = edtDir:GetText(); edtDir:ClearFocus() end)
    local rowsContainer = CreateFrame("Frame", nil, paneCustom); rowsContainer:SetPoint("TOPLEFT", 0, -170); rowsContainer:SetPoint("BOTTOMRIGHT", 0, 0)
    local function CreateBgRow(parent, index, labelText, defaultFile, yOffset)
        local label = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); label:SetPoint("TOPLEFT", 10, yOffset); label:SetText(labelText)
        local edit = CreateFrame("EditBox", nil, parent, "InputBoxTemplate"); edit:SetSize(140, 20); edit:SetPoint("TOPLEFT", 10, yOffset - 15); edit:SetAutoFocus(false)
        if not GR.db.customBackgrounds.files then GR.db.customBackgrounds.files = {} end; edit:SetText(GR.db.customBackgrounds.files[index] or defaultFile or "")
        local btn = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate"); btn:SetSize(40, 20); btn:SetPoint("LEFT", edit, "RIGHT", 5, 0); btn:SetText("Set"); SafeCreateBg(btn, 0, 0, 0, 1); SafeCreateBorder(btn, 0.3, 0.3, 0.3, 1)
        btn:SetScript("OnClick", function() GR.db.customBackgrounds.files[index] = edit:GetText(); edit:ClearFocus() end)
        return edit, btn
    end
    local bgInputs = {}; local y = 0
    if NS.Constants and NS.Constants.TABS then for i = 1, 6 do local tabData = NS.Constants.TABS[i]; local title = tabData and tabData.title or ("Tab " .. i); local e, b = CreateBgRow(rowsContainer, i, title, nil, y); table.insert(bgInputs, {e, b}); y = y - 45 end end
    local e7, b7 = CreateBgRow(rowsContainer, "GuildChat", "Guild Chat", "Background_G-chat.tga", y); table.insert(bgInputs, {e7, b7})
    local function ToggleCustomControls(enable) local alpha = enable and 1 or 0.5; edtDir:SetAlpha(alpha); btnDir:SetAlpha(alpha); rowsContainer:SetAlpha(alpha) end
    chkEnableBg:SetScript("OnClick", function(self) GR.db.customBackgrounds.enabled = self:GetChecked(); ToggleCustomControls(GR.db.customBackgrounds.enabled) end)
    ToggleCustomControls(self.db.customBackgrounds.enabled)

    -- LANGUAGE PANE (Checkbox list like Retail)
    local paneLanguage = CreateFrame("Frame", nil, canvas); paneLanguage:SetPoint("TOPLEFT", paneCustom, "TOPRIGHT", 20, 0); paneLanguage:SetPoint("BOTTOMRIGHT", canvas, "BOTTOMRIGHT", -15, 30); SafeCreateBorder(paneLanguage, 0.3, 0.3, 0.3, 1); SafeCreateBg(paneLanguage, 0.05, 0.05, 0.05, 0.5)
    local hdrLanguage = paneLanguage:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hdrLanguage:SetPoint("TOPLEFT", 10, -15); hdrLanguage:SetText(NS.L["LANGUAGE"] or "Language")
    
    -- Initialize language DB (single selection now stored as string)
    if not self.db.selectedLanguage then self.db.selectedLanguage = nil end
    
    -- Language list with display names and WoW locale keys
    local LANGUAGES = {
        { key = "enUS", label = "English" },
        { key = "deDE", label = "Deutsch" },
        { key = "esES", label = "Español (EU)" },
        { key = "frFR", label = "Français" },
        { key = "itIT", label = "Italiano" },
        { key = "ruRU", label = "Русский" },
        { key = "esMX", label = "Español (AL)" },
        { key = "ptBR", label = "Português" },
        { key = "koKR", label = "한국어" },
        { key = "zhCN", label = "简体中文" },
        { key = "zhTW", label = "繁體中文" },
    }
    
    -- Store references to all checkboxes for radio button behavior
    local langCheckboxes = {}
    
    local langYOffset = -45
    for _, lang in ipairs(LANGUAGES) do
        local chkLang = CreateFrame("CheckButton", "GRS_Settings_Lang_" .. lang.key, paneLanguage, "UICheckButtonTemplate")
        chkLang:SetSize(24, 24); chkLang:SetPoint("TOPLEFT", 10, langYOffset)
        chkLang.text = chkLang:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        chkLang.text:SetPoint("LEFT", chkLang, "RIGHT", 5, 0); chkLang.text:SetText(lang.label)
        chkLang:SetChecked(self.db.selectedLanguage == lang.key)
        chkLang.langKey = lang.key
        langCheckboxes[lang.key] = chkLang
        
        chkLang:SetScript("OnClick", function(cb)
            -- Radio button behavior: uncheck all others
            for key, otherCb in pairs(langCheckboxes) do
                if key ~= cb.langKey then
                    otherCb:SetChecked(false)
                end
            end
            -- Ensure this one stays checked (or allow toggle off)
            if cb:GetChecked() then
                GR.db.selectedLanguage = cb.langKey
            else
                GR.db.selectedLanguage = nil
            end
        end)
        langYOffset = langYOffset - 28
    end
    
    -- Apply Language Button (black rectangular button with white text)
    local btnApplyLang = CreateFrame("Button", nil, paneLanguage, "UIPanelButtonTemplate")
    btnApplyLang:SetSize(140, 30); btnApplyLang:SetPoint("TOPLEFT", 10, langYOffset - 10)
    btnApplyLang:SetText(NS.L["APPLY_LANGUAGE"] or "Apply Language")
    -- Style: Black background, white text
    btnApplyLang:SetNormalTexture("")
    btnApplyLang:SetHighlightTexture("")
    btnApplyLang:SetPushedTexture("")
    btnApplyLang:SetDisabledTexture("")
    if btnApplyLang.Left then btnApplyLang.Left:SetAlpha(0) end
    if btnApplyLang.Middle then btnApplyLang.Middle:SetAlpha(0) end
    if btnApplyLang.Right then btnApplyLang.Right:SetAlpha(0) end
    local btnBg = btnApplyLang:CreateTexture(nil, "BACKGROUND")
    btnBg:SetAllPoints(); btnBg:SetColorTexture(0, 0, 0, 1)
    local btnBorder = btnApplyLang:CreateTexture(nil, "BORDER")
    btnBorder:SetPoint("TOPLEFT", -1, 1); btnBorder:SetPoint("BOTTOMRIGHT", 1, -1); btnBorder:SetColorTexture(0.3, 0.3, 0.3, 1)
    btnApplyLang.bg = btnBg
    if btnApplyLang:GetFontString() then btnApplyLang:GetFontString():SetTextColor(1, 1, 1) end
    btnApplyLang:HookScript("OnEnter", function(s) if s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 1) end end)
    btnApplyLang:HookScript("OnLeave", function(s) if s.bg then s.bg:SetColorTexture(0, 0, 0, 1) end end)
    btnApplyLang:SetScript("OnClick", function()
        local lang = GR.db.selectedLanguage
        if lang then
            print("|cff00ff00A.X.I.O.M.:|r " .. (NS.L["LANGUAGE_SET_TO"] or "Language set to:") .. " " .. lang)
            ReloadUI()
        else
            print("|cff00ff00A.X.I.O.M.:|r " .. (NS.L["NO_LANGUAGE_SELECTED"] or "No language selected."))
        end
    end)
end

function GR:OpenSettings() self._settingsPrevTab = self.activeTab or 1; self:SwitchView(7) end
function GR:CloseSettings() local back = self._settingsPrevTab or 1; if back == 7 then back = 1 end; self:SwitchView(back) end

-- =========================================================================
-- 2. RECOLOR / THEME ENGINE
-- =========================================================================
local function RecursiveColor(frame, theme, depth)
    if not frame or depth > 20 then return end 
    local isButton = frame:IsObjectType("Button")
    if frame.bg and frame.bg.SetColorTexture then if isButton then frame.bg:SetColorTexture(theme.buttons.r, theme.buttons.g, theme.buttons.b, theme.buttons.a) else frame.bg:SetColorTexture(theme.background.r, theme.background.g, theme.background.b, theme.background.a) end end
    if frame.border and frame.border.SetColorTexture then if isButton then frame.border:SetColorTexture(0, 0, 0, 1) else frame.border:SetColorTexture(theme.buttons.r, theme.buttons.g, theme.buttons.b, 1) end end
    if isButton and frame.GetFontString and frame:GetFontString() then frame:GetFontString():SetTextColor(1, 0.82, 0) end
    local children = {frame:GetChildren()}; for _, child in ipairs(children) do if not child:IsForbidden() then RecursiveColor(child, theme, depth + 1) end end
end

function GR:ApplyTheme(inputTheme)
    local t = inputTheme or (self.db and self.db.theme) or { header={r=0.1, g=0.1, b=0.2, a=1}, background={r=0.05, g=0.05, b=0.05, a=0.95}, buttons={r=0.2, g=0.2, b=0.2, a=1} }
    if self.bg then
        local useTexture = false
        if self.db.customBackgrounds and self.db.customBackgrounds.enabled then
            local file = self.db.customBackgrounds.files and self.db.customBackgrounds.files[self.activeTab]
            if file and file ~= "" then local dir = self.db.customBackgrounds.directory; if string.sub(dir, -1) ~= "\\" then dir = dir .. "\\" end; self.bg:SetTexture(dir .. file); self.bg:SetBlendMode("BLEND"); self.bg:SetVertexColor(1, 1, 1, 1); useTexture = true end
        end
        if not useTexture then self.bg:SetTexture(nil); self.bg:SetColorTexture(t.background.r, t.background.g, t.background.b, t.background.a) end
    end
    if self.TitleBar and self.TitleBar.bg then self.TitleBar.bg:SetColorTexture(t.header.r, t.header.g, t.header.b, t.header.a) end
    if self.SideBar and self.SideBar.bg then self.SideBar.bg:SetColorTexture(t.header.r, t.header.g, t.header.b, t.header.a) end
    if self.SettingsCanvas then RecursiveColor(self.SettingsCanvas, t, 0) end
end

-- =========================================================================
-- 3. GUILD IMPORT POPUP LOGIC
-- =========================================================================

function GR:OpenGuildImportPopup(mode)
    if not self.GRMPopup then self:CreateGRMPopup() end
    local f = self.GRMPopup
    f.mode = mode
    f.title:SetText(mode == "IMPORT" and "Import from GuildImport" or "Export for GuildImport")
    f.actionBtn:SetText(mode == "IMPORT" and "Import" or "Export")
    
    if mode == "IMPORT" then
        f.warning:Show()
        f.editBox:SetText(""); f.editBox:Enable()
        if C_GuildInfo and C_GuildInfo.GuildRoster then C_GuildInfo.GuildRoster() elseif _G.GuildRoster then _G.GuildRoster() end
        if GR.FetchGuildData then GR:FetchGuildData(); local count = 0; if GR.GUIDRegistry then for k,v in pairs(GR.GUIDRegistry) do count = count + 1 end end; print("|cff00ff00A.X.I.O.M.:|r Roster Scanned. " .. count .. " GUIDs registered for import.") end
    else
        f.warning:Hide(); f.editBox:SetText(""); f.editBox:Disable() 
    end
    for _, cb in pairs(f.checks) do cb:SetChecked(false) end
    f.actionBtn:Disable(); f:Show()
end

function GR:CreateGRMPopup()
    local f = CreateFrame("Frame", "GRS_GRM_Popup", UIParent, "BackdropTemplate")
    f:SetSize(600, 500); f:SetPoint("CENTER"); f:SetFrameStrata("FULLSCREEN_DIALOG"); f:EnableMouse(true); f:SetMovable(true); f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving); f:SetScript("OnDragStop", f.StopMovingOrSizing)
    local bg = f:CreateTexture(nil, "BACKGROUND"); bg:SetAllPoints(); bg:SetTexture("Interface\\AddOns\\GuildRecruiterManagement\\RaidRoster\\Import_BG.tga"); f.bg = bg
    local overlay = f:CreateTexture(nil, "BORDER"); overlay:SetAllPoints(); overlay:SetColorTexture(0, 0, 0, 0.2); f.overlay = overlay
    SafeCreateBorder(f, 0.3, 0.3, 0.3, 1)

    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); f.title:SetPoint("TOP", 0, -15)
    f.warning = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); f.warning:SetPoint("TOP", 0, -40); f.warning:SetText("|cffff0000Please only import the data WITHOUT headers. The addon is configured with delimiters.|r"); f.warning:SetWidth(550); f.warning:SetWordWrap(true)
    
    local chkContainer = CreateFrame("Frame", nil, f); chkContainer:SetSize(550, 150); chkContainer:SetPoint("TOP", 0, -70)
    f.checks = {}; local x, y = 10, 0; local colCount = 0
    for i, field in ipairs(GR.GUILD_IMPORT_FIELDS) do
        local cb = CreateFrame("CheckButton", nil, chkContainer, "UICheckButtonTemplate"); cb:SetPoint("TOPLEFT", x, y)
        cb.text:SetText(field.label); cb.text:SetTextColor(1, 1, 1); cb.fieldIdx = field.idx; cb.key = field.key
        cb:SetScript("OnClick", function() local anyChecked = false; for _, c in pairs(f.checks) do if c:GetChecked() then anyChecked = true break end end; if anyChecked then f.actionBtn:Enable() else f.actionBtn:Disable() end end)
        f.checks[field.key] = cb; colCount = colCount + 1; if colCount >= 3 then colCount = 0; x = 10; y = y - 25 else x = x + 180 end
    end
    
    local scroll = CreateFrame("ScrollFrame", "GRS_GRM_Scroll", f, "UIPanelScrollFrameTemplate"); scroll:SetPoint("TOPLEFT", 20, -260); scroll:SetPoint("BOTTOMRIGHT", -40, 60); SafeCreateBg(scroll, 0, 0, 0, 0.5)
    if NS.StyleScrollBar then NS.StyleScrollBar(scroll) end
    scroll:EnableMouse(true); scroll:SetScript("OnMouseDown", function() if f.editBox then f.editBox:SetFocus() end end)
    local eb = CreateFrame("EditBox", nil, scroll); eb:SetMultiLine(true); eb:SetFontObject("ChatFontNormal"); eb:SetWidth(scroll:GetWidth() - 20); eb:SetHeight(200); eb:SetAutoFocus(false); scroll:SetScrollChild(eb); f.editBox = eb
    
    local btnAction = CreateFrame("Button", nil, f, "UIPanelButtonTemplate"); btnAction:SetSize(120, 30); btnAction:SetPoint("BOTTOMLEFT", 20, 20); SafeSkinButton(btnAction); f.actionBtn = btnAction
    btnAction:SetScript("OnClick", function()
        if f.mode == "IMPORT" then
            GR:ProcessGuildImport(f.editBox:GetText(), f.checks)
            f:Hide()
        else
            f.editBox:SetText(GR:GenerateGuildExport(f.checks)); f.editBox:HighlightText(); f.editBox:SetFocus()
        end
    end)
    local btnClose = CreateFrame("Button", nil, f, "UIPanelButtonTemplate"); btnClose:SetSize(120, 30); btnClose:SetPoint("BOTTOMRIGHT", -20, 20); btnClose:SetText("Close"); SafeSkinButton(btnClose); btnClose:SetScript("OnClick", function() f:Hide() end)
    self.GRMPopup = f
end

-- =========================================================================
-- 4. IMPORT / EXPORT DATA LOGIC
-- =========================================================================

function GR:ProcessGuildImport(text, checks)
    if not text or text == "" then return end
    local count = 0
    local skipped = 0
    
    if not GRS_SocialDB then GRS_SocialDB = {} end
    if not GRS_IdentityDB then GRS_IdentityDB = {} end
    if not GRS_IdentityDB.mains then GRS_IdentityDB.mains = {} end
    if not GRS_IdentityDB.alts then GRS_IdentityDB.alts = {} end
    if not GRS_IdentityDB.factions then GRS_IdentityDB.factions = {} end
    if not GRS_IdentityDB.times then GRS_IdentityDB.times = {} end
    GRS_IdentityDB.ghostFinished = true

    local rosterMap = {}
    local num = GetNumGuildMembers()
    for i = 1, num do
        local fullName = GetGuildRosterInfo(i)
        if fullName then local short = Ambiguate(fullName, "none"); local canonical = GR:GetCanonicalName(fullName); rosterMap[short] = canonical end
    end
    if not GR.GUIDRegistry or next(GR.GUIDRegistry) == nil then GR:FetchGuildData() end
    
    for line in string.gmatch(text, "[^\r\n]+") do
        local cols = { strsplit(";", line) }
        local rawName = cols[1]; local guid = cols[20]
        local mainAltStatus = cols[8]; local altsList = cols[9]
        local raceInput = cols[5]
        
        local targetKey = nil
        if guid and guid ~= "" and GR.GUIDRegistry[guid] then targetKey = GR.GUIDRegistry[guid]
        elseif rawName and rawName ~= "" then local shortImport = Ambiguate(rawName, "none"); targetKey = rosterMap[shortImport] end
        
        if targetKey then
            if not GRS_SocialDB[targetKey] then GRS_SocialDB[targetKey] = {} end
            local sData = GRS_SocialDB[targetKey]
            
            if GR.DetermineFaction then
                local faction = GR:DetermineFaction(raceInput)
                GRS_IdentityDB.factions[targetKey] = faction
            end
            
            local timestamp = GetServerTime()
            if mainAltStatus == "Main" then
                GRS_IdentityDB.mains[targetKey] = true; GRS_IdentityDB.alts[targetKey] = nil; GRS_IdentityDB.times[targetKey] = timestamp
            elseif mainAltStatus == "Alt" then
                if altsList and altsList ~= "" then
                    for entry in string.gmatch(altsList, "([^,]+)") do
                        if string.find(entry, "%(main%)") then
                            local parentRaw = string.gsub(entry, "%(main%)", "")
                            parentRaw = parentRaw:gsub("^%s*(.-)%s*$", "%1") 
                            local parentKey = nil
                            local parentShort = Ambiguate(parentRaw, "none")
                            if rosterMap[parentShort] then parentKey = rosterMap[parentShort]
                            elseif GR:GetCanonicalName(parentRaw) then parentKey = parentRaw end
                            
                            if parentKey and parentKey ~= targetKey then
                                GRS_IdentityDB.mains[targetKey] = nil; GRS_IdentityDB.alts[targetKey] = parentKey; GRS_IdentityDB.times[targetKey] = timestamp
                            end
                            break
                        end
                    end
                end
            end

            if checks["Birthday"] and checks["Birthday"]:GetChecked() then local m, d = ParseImportDate(cols[13]); if m and d then sData.birthMonth = m; sData.birthDay = d end end
            if checks["JoinDate"] and checks["JoinDate"]:GetChecked() then local m, d = ParseImportDate(cols[10]); if m and d then sData.joinMonth = m; sData.joinDay = d end end
            if checks["PromoDate"] and checks["PromoDate"]:GetChecked() then local m, d = ParseImportDate(cols[11]); if m and d then sData.promMonth = m; sData.promDay = d end end
            if checks["PubNote"] and checks["PubNote"]:GetChecked() and cols[15] ~= "" then sData.pubNote = cols[15] end
            if checks["OffNote"] and checks["OffNote"]:GetChecked() and cols[16] ~= "" then sData.offNote = cols[16] end
            if checks["CustNote"] and checks["CustNote"]:GetChecked() and cols[17] ~= "" then sData.customNote = cols[17] end
            count = count + 1
        else skipped = skipped + 1 end
    end
    print("|cff00ff00A.X.I.O.M.:|r Imported data for " .. count .. " players.")
    if skipped > 0 then print("|cffff0000A.X.I.O.M.:|r Skipped " .. skipped .. " entries (No match found).") end
    if GR.UpdateRosterList then GR:UpdateRosterList() end
    if GR.PerformSync then GR:PerformSync(true) end
end

function GR:GenerateGuildExport(checks)
    local out = ""
    local num = GetNumGuildMembers()
    for i = 1, num do
        local name, rank, rankIndex, level, class, zone, pubNote, offNote, online, status, classFileName = GetGuildRosterInfo(i)
        if name then
            local cName = GR:GetCanonicalName(name)
            local sData = GRS_SocialDB and GRS_SocialDB[cName] or {}
            local guid = UnitGUID(name) or ""
            
            local f = {}; for j=1, 20 do f[j] = "" end
            if checks["Name"] and checks["Name"]:GetChecked() then f[1] = Ambiguate(name, "none") end
            if checks["Rank"] and checks["Rank"]:GetChecked() then f[2] = rank end
            if checks["Level"] and checks["Level"]:GetChecked() then f[3] = level end
            if checks["Class"] and checks["Class"]:GetChecked() then f[4] = class end
            if checks["Race"] and checks["Race"]:GetChecked() then f[5] = sData.raceSex or "Unknown" end
            if checks["Sex"] and checks["Sex"]:GetChecked() then f[6] = "Male" end
            if checks["LastOnline"] and checks["LastOnline"]:GetChecked() then local y, m, d, h = GetGuildRosterLastOnline(i); local days = (y or 0)*365 + (m or 0)*30 + (d or 0) + (h or 0)/24; f[7] = string.format("%.2f", days) end
            
            local isMain, parent = GR:GetIdentity(cName)
            if checks["MainAlt"] and checks["MainAlt"]:GetChecked() then f[8] = isMain and "Main" or "Alt" end
            if checks["Alts"] and checks["Alts"]:GetChecked() then 
                if isMain then
                    -- If we are main, list children logic could go here
                else
                     if parent then f[9] = parent .. "(main)" end
                end
            end 
            
            if checks["JoinDate"] and checks["JoinDate"]:GetChecked() then f[10] = FormatImportDate(sData.joinDay, sData.joinMonth) end
            if checks["PromoDate"] and checks["PromoDate"]:GetChecked() then f[11] = FormatImportDate(sData.promDay, sData.promMonth) end
            if checks["Birthday"] and checks["Birthday"]:GetChecked() then f[13] = FormatImportDate(sData.birthDay, sData.birthMonth) end
            if checks["Rep"] and checks["Rep"]:GetChecked() then f[14] = "Neutral" end
            if checks["PubNote"] and checks["PubNote"]:GetChecked() then f[15] = pubNote end
            if checks["OffNote"] and checks["OffNote"]:GetChecked() then f[16] = offNote end
            if checks["CustNote"] and checks["CustNote"]:GetChecked() then f[17] = sData.customNote or "" end
            -- M+ Score removed for TBC (field 18 stays empty)
            if checks["Faction"] and checks["Faction"]:GetChecked() then 
                f[19] = (GRS_IdentityDB and GRS_IdentityDB.factions and GRS_IdentityDB.factions[cName]) or "Neutral" 
            end
            if checks["GUID"] and checks["GUID"]:GetChecked() then f[20] = guid end
            out = out .. table.concat(f, ";") .. "\n"
        end
    end
    return out
end

-- =========================================================================
-- 5. INITIALIZATION & HOOKS
-- =========================================================================

hooksecurefunc(GR, "SwitchView", function(self, viewIndex) if not self.db or not self.db.theme then return end; self:ApplyTheme(nil) end)
hooksecurefunc(GR, "Initialize", function(self)
    C_Timer.After(0.2, function()
        if not self.db.theme then self.db.theme = {} end
        local d = self.db.theme
        if not d.header then d.header = {r=0.1, g=0.1, b=0.2, a=1} end
        if not d.background then d.background = {r=0.05, g=0.05, b=0.05, a=0.95} end
        if not d.buttons then d.buttons = {r=0.2, g=0.2, b=0.2, a=1} end
        self:ApplyTheme(nil)
        
        -- [[ COMPACT MODE INIT ]]
        if GR.db.compactMode and GR.ToggleCompactMode then
            GR:ToggleCompactMode(true)
        end
    end)
end)