-- =========================================================================
-- FILE: Settings.lua
-- =========================================================================
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: SafeCreateBg, SafeCreateBorder, SafeSkinButton, CreateColorSlider omitted for brevity but present in execution] ...
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 (Renamed)
-- =========================================================================

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 },
    { key = "MScore", label = "Mythic+ Score", idx = 18 },
    { 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

    -- Custom Column Visibility defaults
    if not self.db.customColumns then
        self.db.customColumns = {
            grs    = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false },
            roster = { ach=true, ilvl=true, rio=true, raidN=true, raidH=true, raidM=true, maxKey=false },
            socialGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false },
            raidGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false },
            mplusGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false },
        }
    end
    if not self.db.customColumns.socialGrs then
        self.db.customColumns.socialGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false }
    end
    if not self.db.customColumns.raidGrs then
        self.db.customColumns.raidGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false }
    end
    if not self.db.customColumns.mplusGrs then
        self.db.customColumns.mplusGrs = { zone=true, maxKey=true, rio=true, warbandScore=false, raidN=true, heroic=true, mythic=false }
    end

    if not self.db.customColumns.pvpRoster then
        self.db.customColumns.pvpRoster = { pvp2v2=true, pvp3v3=true, pvpSolo=true, pvpRbg=true, pvpBest=true, pvpExp=true, pvpSpec=true }
    end

    local parent = CreateFrame("Frame", "GRS_SettingsView", self.ViewContainer)
    parent:SetAllPoints(); parent:Hide(); self.views[7] = parent

    local function UpdateLiveTheme() GR:ApplyTheme(nil) end

    -- =================================================================
    -- HELPER: Styled Checkbox (dark UI-themed toggle)
    -- =================================================================
    local function CreateStyledCheckbox(parentFrame, label, anchorPoint, anchorRelTo, anchorRelPt, xOff, yOff)
        local f = CreateFrame("Button", nil, parentFrame)
        f:SetSize(20, 20)
        if anchorRelTo then
            f:SetPoint(anchorPoint or "TOPLEFT", anchorRelTo, anchorRelPt or "TOPLEFT", xOff or 0, yOff or 0)
        else
            f:SetPoint(anchorPoint or "TOPLEFT", xOff or 0, yOff or 0)
        end
        -- Box background
        local box = f:CreateTexture(nil, "BORDER"); box:SetAllPoints(); box:SetColorTexture(0.08, 0.08, 0.08, 1); f.box = box
        local brd = f:CreateTexture(nil, "BACKGROUND"); brd:SetPoint("TOPLEFT", -1, 1); brd:SetPoint("BOTTOMRIGHT", 1, -1); brd:SetColorTexture(0.35, 0.35, 0.35, 1); f.brd = brd
        -- Check mark (gold)
        local mark = f:CreateTexture(nil, "ARTWORK"); mark:SetSize(14, 14); mark:SetPoint("CENTER"); mark:SetColorTexture(0.85, 0.65, 0, 1); mark:Hide(); f.mark = mark
        -- Label
        if label then
            local txt = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); txt:SetPoint("LEFT", f, "RIGHT", 6, 0); txt:SetText(label); txt:SetTextColor(0.9, 0.9, 0.9); f.label = txt
        end
        f.checked = false
        f.SetChecked = function(self, val) self.checked = val; if val then self.mark:Show(); self.brd:SetColorTexture(0.85, 0.65, 0, 1) else self.mark:Hide(); self.brd:SetColorTexture(0.35, 0.35, 0.35, 1) end end
        f.GetChecked = function(self) return self.checked end
        f:SetScript("OnClick", function(self)
            self.checked = not self.checked
            self:SetChecked(self.checked)
            if self.onClickHandler then self:onClickHandler() end
        end)
        f:SetScript("OnEnter", function(self) if not self.checked then self.box:SetColorTexture(0.15, 0.15, 0.15, 1) end end)
        f:SetScript("OnLeave", function(self) if not self.checked then self.box:SetColorTexture(0.08, 0.08, 0.08, 1) end end)
        return f
    end

    -- =================================================================
    -- HELPER: Custom Styled Dropdown
    -- =================================================================
    local function CreateStyledDropdown(parentFrame, width, items, currentVal, onChange)
        local dd = CreateFrame("Frame", nil, parentFrame)
        dd:SetSize(width, 28)
        SafeCreateBg(dd, 0.06, 0.06, 0.06, 1); SafeCreateBorder(dd, 0.3, 0.3, 0.3, 1)
        local selected = dd:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); selected:SetPoint("LEFT", 10, 0); selected:SetTextColor(1, 1, 1)
        local arrow = dd:CreateFontString(nil, "OVERLAY", "GameFontNormal"); arrow:SetPoint("RIGHT", -8, 0); arrow:SetText("\226\150\188"); arrow:SetTextColor(0.7, 0.7, 0.7)
        dd.selectedValue = currentVal
        -- Find label for current value
        local function UpdateLabel()
            for _, item in ipairs(items) do
                if item.id == dd.selectedValue then selected:SetText(item.label); return end
            end
            selected:SetText(items[1] and items[1].label or "---")
        end
        UpdateLabel()

        -- Dropdown list (initially hidden)
        local list = CreateFrame("Frame", nil, dd)
        list:SetWidth(width); list:SetPoint("TOPLEFT", dd, "BOTTOMLEFT", 0, -2)
        list:SetFrameStrata("FULLSCREEN_DIALOG"); list:SetFrameLevel(200)
        SafeCreateBg(list, 0.05, 0.05, 0.05, 0.98); SafeCreateBorder(list, 0.3, 0.3, 0.3, 1)
        list:Hide(); dd.list = list

        local totalH = 4
        for _, item in ipairs(items) do
            local row = CreateFrame("Button", nil, list)
            row:SetSize(width - 4, 24); row:SetPoint("TOPLEFT", 2, -totalH)
            local rowBg = row:CreateTexture(nil, "BORDER"); rowBg:SetAllPoints(); rowBg:SetColorTexture(0, 0, 0, 0); row.rowBg = rowBg
            local rowTxt = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); rowTxt:SetPoint("LEFT", 8, 0); rowTxt:SetText(item.label); rowTxt:SetTextColor(0.85, 0.85, 0.85)
            -- Glow on hover
            row:SetScript("OnEnter", function(s) s.rowBg:SetColorTexture(0.15, 0.12, 0.02, 0.8) end)
            row:SetScript("OnLeave", function(s) s.rowBg:SetColorTexture(0, 0, 0, 0) end)
            row:SetScript("OnClick", function()
                dd.selectedValue = item.id; UpdateLabel(); list:Hide()
                if onChange then onChange(item.id) end
            end)
            totalH = totalH + 24
        end
        list:SetHeight(totalH + 4)

        -- Toggle list on click
        dd:EnableMouse(true)
        dd:SetScript("OnMouseDown", function() if list:IsShown() then list:Hide() else list:Show() end end)
        dd:SetScript("OnEnter", function() dd.bg:SetColorTexture(0.1, 0.1, 0.1, 1) end)
        dd:SetScript("OnLeave", function() dd.bg:SetColorTexture(0.06, 0.06, 0.06, 1) end)
        -- Close when clicking elsewhere
        list:SetScript("OnShow", function(self) self:SetScript("OnUpdate", function(self)
            if not dd:IsMouseOver() and not self:IsMouseOver() then self:Hide() end
        end) end)
        list:SetScript("OnHide", function(self) self:SetScript("OnUpdate", nil) end)

        dd.SetValue = function(self, val) self.selectedValue = val; UpdateLabel() end
        dd.GetValue = function(self) return self.selectedValue end
        return dd
    end

    -- =================================================================
    -- HELPER: Nav Button (black bg, white label, gold active border)
    -- =================================================================
    local function CreateNavButton(parentFrame, label, yOffset)
        local btn = CreateFrame("Button", nil, parentFrame)
        btn:SetSize(225, 30); btn:SetPoint("TOPLEFT", 10, yOffset)
        btn:SetNormalTexture(""); btn:SetHighlightTexture(""); btn:SetPushedTexture("")
        local bg = btn:CreateTexture(nil, "BORDER"); bg:SetAllPoints(); bg:SetColorTexture(0, 0, 0, 1); btn.bg = bg
        local brd = btn:CreateTexture(nil, "BACKGROUND"); brd:SetPoint("TOPLEFT", -1, 1); brd:SetPoint("BOTTOMRIGHT", 1, -1); brd:SetColorTexture(0.3, 0.3, 0.3, 1); btn.brd = brd
        local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal"); txt:SetPoint("LEFT", 10, 0); txt:SetText(label); txt:SetTextColor(1, 1, 1); btn.label = txt
        btn.isActive = false
        btn:SetScript("OnEnter", function(s) if not s.isActive and s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 1) end end)
        btn:SetScript("OnLeave", function(s) if not s.isActive and s.bg then s.bg:SetColorTexture(0, 0, 0, 1) end end)
        return btn
    end

    -- =================================================================
    -- HELPER: Option Pane (title + description, inside a scroll canvas)
    -- =================================================================
    local function CreateOptionPane(canvas, yOffset, title, description, paneHeight)
        local pane = CreateFrame("Frame", nil, canvas)
        pane:SetPoint("TOPLEFT", 10, yOffset); pane:SetPoint("RIGHT", canvas, "RIGHT", -10, 0)
        pane:SetHeight(paneHeight or 70)
        SafeCreateBg(pane, 0.08, 0.08, 0.08, 0.7); SafeCreateBorder(pane, 0.2, 0.2, 0.2, 1)
        local t = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal"); t:SetPoint("TOPLEFT", 10, -8); t:SetText(title); pane.title = t
        if description then
            local dc = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); dc:SetPoint("TOPLEFT", 10, -26); dc:SetPoint("RIGHT", pane, "RIGHT", -50, 0); dc:SetJustifyH("LEFT"); dc:SetText(description); dc:SetTextColor(0.6, 0.6, 0.6); pane.desc = dc
        end
        return pane
    end

    -- =================================================================
    -- HELPER: Scrollable Sub-Page
    -- =================================================================
    local function CreateSubPage(parentFrame)
        local page = CreateFrame("Frame", nil, parentFrame); page:SetAllPoints(); page:Hide()
        local scroll = CreateFrame("ScrollFrame", nil, page, "UIPanelScrollFrameTemplate")
        scroll:SetPoint("TOPLEFT", 5, -5); scroll:SetPoint("BOTTOMRIGHT", -28, 5)
        if NS.StyleScrollBar then NS.StyleScrollBar(scroll) end
        local canvas = CreateFrame("Frame", nil, scroll); canvas:SetWidth(750); canvas:SetHeight(600)
        scroll:SetScrollChild(canvas)
        scroll:SetScript("OnSizeChanged", function(self, w) canvas:SetWidth(w) end)
        page.scroll = scroll; page.canvas = canvas
        return page
    end

    -- =================================================================
    -- LEFT SIDEBAR (245px)
    -- =================================================================
    local sidebar = CreateFrame("Frame", nil, parent)
    sidebar:SetWidth(245); sidebar:SetPoint("TOPLEFT", 0, -30); sidebar:SetPoint("BOTTOMLEFT", 0, 0)
    SafeCreateBg(sidebar, 0.05, 0.05, 0.05, 0.95); SafeCreateBorder(sidebar, 0.2, 0.2, 0.2, 1)

    -- =================================================================
    -- CENTER PANEL
    -- =================================================================
    local center = CreateFrame("Frame", nil, parent)
    center:SetPoint("TOPLEFT", sidebar, "TOPRIGHT", 0, 0); center:SetPoint("BOTTOMRIGHT", 0, 0)
    SafeCreateBg(center, 0.06, 0.06, 0.06, 0.9)
    self.SettingsCanvas = center

    -- =================================================================
    -- CREATE 6 SUB-PAGES
    -- =================================================================
    local pages = {}
    for i = 1, 6 do pages[i] = CreateSubPage(center) end

    -- =================================================================
    -- NAV BUTTONS
    -- =================================================================
    local categories = {
        NS.L["GENERAL_SETTINGS"] or "General Settings",
        NS.L["UI_MODE"] or "UI Mode",
        NS.L["APPEARANCES"] or "Appearances",
        NS.L["TOOLS"] or "Tools",
        NS.L["LANGUAGE"] or "Language",
        NS.L["ADVANCED"] or "Advanced",
    }
    local navBtns = {}
    local function SelectCategory(index)
        for i = 1, 6 do
            if i == index then
                pages[i]:Show(); navBtns[i].isActive = true
                navBtns[i].bg:SetColorTexture(0.15, 0.15, 0.15, 1); navBtns[i].brd:SetColorTexture(0.8, 0.6, 0, 1)
            else
                pages[i]:Hide(); navBtns[i].isActive = false
                navBtns[i].bg:SetColorTexture(0, 0, 0, 1); navBtns[i].brd:SetColorTexture(0.3, 0.3, 0.3, 1)
            end
        end
    end
    for i, cat in ipairs(categories) do
        local btn = CreateNavButton(sidebar, cat, -15 - ((i - 1) * 40))
        btn:SetScript("OnClick", function() SelectCategory(i) end)
        navBtns[i] = btn
    end

    -- =================================================================
    -- PAGE 1: GENERAL SETTINGS
    -- =================================================================
    do
        local c = pages[1].canvas; local y = -10

        -- Minimap Button
        local p1 = CreateOptionPane(c, y, NS.L["MINIMAP_BUTTON"] or "Minimap Button", "Show or hide the A.X.I.O.M. minimap icon. When hidden, use /axiom to open.", 70)
        local chkMini = CreateStyledCheckbox(p1, "Enabled", "TOPLEFT", nil, nil, 10, -45)
        chkMini:SetChecked(self.db.minimapShown ~= false)
        chkMini.onClickHandler = function(cb) GR.db.minimapShown = cb:GetChecked(); if _G["GRS_MinimapButton"] then if GR.db.minimapShown then _G["GRS_MinimapButton"]:Show() else _G["GRS_MinimapButton"]:Hide() end end end
        y = y - 75

        -- Auto-Open + Default Tab (MERGED)
        local p2 = CreateOptionPane(c, y, NS.L["AUTO_OPEN"] or "Auto-Open & Default Tab", "Configure whether the addon auto-opens on login and which tab it defaults to.", 110)
        local chkAuto = CreateStyledCheckbox(p2, "Auto-Open on Login", "TOPLEFT", nil, nil, 10, -45)
        chkAuto:SetChecked(self.db.autoOpen or false)
        chkAuto.onClickHandler = function(cb) GR.db.autoOpen = cb:GetChecked() end

        -- Default Tab dropdown
        local ddLabel = p2:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); ddLabel:SetPoint("TOPLEFT", 10, -75); ddLabel:SetText("Default Tab:"); ddLabel:SetTextColor(0.7, 0.7, 0.7)
        local tabItems = {}
        for _, tab in ipairs(NS.Constants.TABS) do if tab.id ~= 7 and tab.id ~= 8 then tabItems[#tabItems + 1] = { id = tab.id, label = NS.GetTabTitle(tab) } end end
        if not self.db.defaultTab then self.db.defaultTab = 1 end
        local ddTab = CreateStyledDropdown(p2, 220, tabItems, self.db.defaultTab, function(val) GR.db.defaultTab = val end)
        ddTab:SetPoint("LEFT", ddLabel, "RIGHT", 10, 0)
        y = y - 115

        -- Level Range Defaults
        local p3 = CreateOptionPane(c, y, NS.L["LEVEL_RANGE"] or "Level Range Defaults", "Default minimum and maximum level range used for recruitment scans.", 90)
        local lblMin = p3:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); lblMin:SetPoint("TOPLEFT", 10, -50); lblMin:SetText("Min: " .. (self.db.levelMin or 1))
        local sMin = CreateFrame("Slider", "GRS_Set_LvlMin", p3, "OptionsSliderTemplate"); sMin:SetPoint("TOPLEFT", 60, -48); sMin:SetWidth(260); sMin:SetMinMaxValues(1, 80); sMin:SetValueStep(1); sMin:SetObeyStepOnDrag(true); sMin:SetValue(self.db.levelMin or 1)
        local sn1 = sMin:GetName(); if _G[sn1.."Low"] then _G[sn1.."Low"]:SetText("") end; if _G[sn1.."High"] then _G[sn1.."High"]:SetText("") end; if _G[sn1.."Text"] then _G[sn1.."Text"]:SetText("") end
        sMin:SetScript("OnValueChanged", function(s, v) lblMin:SetText("Min: " .. math.floor(v)) end)
        sMin:SetScript("OnMouseUp", function(s) GR.db.levelMin = math.floor(s:GetValue()) end)
        local lblMax = p3:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); lblMax:SetPoint("TOPLEFT", 380, -50); lblMax:SetText("Max: " .. (self.db.levelMax or 80))
        local sMax = CreateFrame("Slider", "GRS_Set_LvlMax", p3, "OptionsSliderTemplate"); sMax:SetPoint("TOPLEFT", 430, -48); sMax:SetWidth(260); sMax:SetMinMaxValues(1, 80); sMax:SetValueStep(1); sMax:SetObeyStepOnDrag(true); sMax:SetValue(self.db.levelMax or 80)
        local sn2 = sMax:GetName(); if _G[sn2.."Low"] then _G[sn2.."Low"]:SetText("") end; if _G[sn2.."High"] then _G[sn2.."High"]:SetText("") end; if _G[sn2.."Text"] then _G[sn2.."Text"]:SetText("") end
        sMax:SetScript("OnValueChanged", function(s, v) lblMax:SetText("Max: " .. math.floor(v)) end)
        sMax:SetScript("OnMouseUp", function(s) GR.db.levelMax = math.floor(s:GetValue()) end)
        y = y - 95

        -- Sound / Notification Toggles (with actual functionality)
        local p4 = CreateOptionPane(c, y, NS.L["SOUND_NOTIFICATIONS"] or "Sound / Notification Toggles", "Mute whisper sounds, recruitment alerts, and other notification sounds.", 80)
        local chkW = CreateStyledCheckbox(p4, NS.L["MUTE_WHISPER"] or "Mute Whisper Sounds", "TOPLEFT", nil, nil, 10, -50)
        chkW:SetChecked(self.db.muteWhisper or false)
        chkW.onClickHandler = function(cb)
            GR.db.muteWhisper = cb:GetChecked()
            if GR.db.muteWhisper then
                MuteSoundFile(3081) -- Whisper received sound
            else
                UnmuteSoundFile(3081)
            end
        end
        local chkA = CreateStyledCheckbox(p4, NS.L["MUTE_ALERTS"] or "Mute Recruitment Alerts", "LEFT", chkW.label, "RIGHT", 30, 0)
        chkA:SetChecked(self.db.muteAlerts or false)
        chkA.onClickHandler = function(cb) GR.db.muteAlerts = cb:GetChecked() end
        y = y - 85

        c:SetHeight(math.abs(y) + 20)
    end

    -- =================================================================
    -- PAGE 2: UI MODE (radio-style, checkboxes in front)
    -- =================================================================
    do
        local c = pages[2].canvas; local y = -10
        if not self.db.guildMode then self.db.guildMode = self.db.socialEnabled and "social" or nil end
        local modeCheckboxes = {}
        local modeApplyBtns = {}
        local modes = {
            { key = "social",  label = NS.L["SOCIAL_GUILD_MODE"] or "Social Guild Mode",  desc = "Activates a variety of options and insights into your members, set personal notes, anniversaries, birthdays and more." },
            { key = "raid",    label = NS.L["RAID_GUILD_MODE"] or "Raid Guild Mode",      desc = "Activates a variety of options with great insight into your members progression and commitment to the guild." },
            { key = "pvp",     label = NS.L["PVP_GUILD_MODE"] or "PVP Guild Mode",        desc = "Activates a variety of options with great insight into your members PVP experience and Achievements." },
            { key = "mplus",   label = NS.L["MPLUS_GUILD_MODE"] or "M+ Guild Mode",       desc = "Activates a variety of options with great insight into your members Mythic Plus races." },
            { key = "custom",  label = NS.L["CUSTOM_GUILD_MODE"] or "Custom Guild Mode",  desc = "Set and create your own Guild mode, which insights do you find important?" },
        }
        for _, mode in ipairs(modes) do
            local paneHeight = 70
            if mode.key == "custom" then paneHeight = 380 end
            if mode.key == "social" then paneHeight = 280 end
            if mode.key == "raid" then paneHeight = 280 end
            if mode.key == "mplus" then paneHeight = 280 end
            if mode.key == "pvp" then paneHeight = 280 end
            local pane = CreateOptionPane(c, y, mode.label, mode.desc, paneHeight)
            local chk = CreateStyledCheckbox(pane, nil, "TOPLEFT", nil, nil, 10, -8)
            chk:SetChecked(self.db.guildMode == mode.key)
            chk.modeKey = mode.key
            modeCheckboxes[mode.key] = chk
            -- Shift the title right to make room for checkbox
            pane.title:ClearAllPoints(); pane.title:SetPoint("TOPLEFT", 38, -8)
            if pane.desc then pane.desc:ClearAllPoints(); pane.desc:SetPoint("TOPLEFT", 38, -26); pane.desc:SetPoint("RIGHT", pane, "RIGHT", -10, 0) end

            -- Mode pane background image
            local modeBgPaths = {
                social = "Interface\\AddOns\\GuildRecruiterManagement\\Media\\Social_Guild",
                raid   = "Interface\\AddOns\\GuildRecruiterManagement\\Media\\Raiding_Guild",
                pvp    = "Interface\\AddOns\\GuildRecruiterManagement\\Media\\PVP_Guild",
                mplus  = "Interface\\AddOns\\GuildRecruiterManagement\\Media\\M+_Guild",
            }
            if modeBgPaths[mode.key] then
                local bgTex = pane:CreateTexture(nil, "ARTWORK", nil, -1)
                bgTex:SetTexture(modeBgPaths[mode.key])
                bgTex:SetSize(750, 320)
                bgTex:SetPoint("RIGHT", pane, "RIGHT", 0, 0)
                bgTex:SetAlpha(0.65)
                bgTex:SetTexCoord(0, 1, 0, 1)
            end
            chk.onClickHandler = function(cb)
                if cb:GetChecked() then
                    GR.db.guildMode = cb.modeKey
                    for k, other in pairs(modeCheckboxes) do if k ~= cb.modeKey then other:SetChecked(false) end end
                    GR.db.socialEnabled = (cb.modeKey == "social")
                else
                    GR.db.guildMode = nil; GR.db.socialEnabled = false
                end
                -- Enable/Disable Apply buttons based on active mode
                for k, btn in pairs(modeApplyBtns) do
                    if GR.db.guildMode == k then btn:Enable() else btn:Disable() end
                end
                if GR.UpdateRosterList then GR:UpdateRosterList() end
                -- Rebuild GRS center pane so column visibility matches the new mode
                local cp = _G["GRS_CenterPane"]
                if cp then
                    local kids = { cp:GetChildren() }
                    for _, child in ipairs(kids) do child:Hide(); child:SetParent(nil) end
                    local regions = { cp:GetRegions() }
                    for _, r in ipairs(regions) do r:Hide(); r:SetParent(nil) end
                    GR.ResultsHeader = nil; GR.SearchBtn = nil; GR.StatusText = nil
                    GR.grsVisibleCols = nil; GR.rows = {}; GR.scroll = nil; GR.listBackdrop = nil
                    GR:BuildCenterPane(cp)
                    if GR.UpdateHomeLayout then GR.UpdateHomeLayout() end
                end
            end

            -- =============================================================
            -- SOCIAL GUILD MODE: GRS Column Configuration
            -- =============================================================
            if mode.key == "social" then
                local cc = self.db.customColumns

                local function CountEnabledSocial(tbl)
                    local n = 0
                    for _, v in pairs(tbl) do if v then n = n + 1 end end
                    return n
                end

                -- ---- GRS Columns (max 5 of 6) ----
                local sgrsTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                sgrsTitle:SetPoint("TOPLEFT", 10, -50); sgrsTitle:SetText("GRS Columns (max 5)"); sgrsTitle:SetTextColor(1, 0.82, 0)
                local sgrsCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                sgrsCounter:SetPoint("LEFT", sgrsTitle, "RIGHT", 10, 0); sgrsCounter:SetTextColor(0.7, 0.7, 0.7)

                local SGRS_COLS = {
                    { key = "zone",   label = "Zone" },
                    { key = "maxKey", label = "M+ (Max Key)" },
                    { key = "rio",    label = "Score" },
                    { key = "raidN",  label = "Normal" },
                    { key = "heroic", label = "Heroic" },
                    { key = "mythic", label = "Mythic" },
                    { key = "warbandScore", label = "Warband Score" },
                }
                local sgrsCbs = {}
                local function UpdateSocialGrsCounter()
                    sgrsCounter:SetText(CountEnabledSocial(cc.socialGrs) .. "/5 selected")
                end
                local sgrsCols = 3; local sgrsStartY = -70; local sgrsStartX = 10; local sgrsColW = 180; local sgrsRowH = 28
                for idx, col in ipairs(SGRS_COLS) do
                    local colIdx = (idx - 1) % sgrsCols; local rowIdx = math.floor((idx - 1) / sgrsCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, sgrsStartX + (colIdx * sgrsColW), sgrsStartY - (rowIdx * sgrsRowH))
                    cb:SetChecked(cc.socialGrs[col.key] ~= false)
                    cb.colKey = col.key
                    sgrsCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabledSocial(cc.socialGrs) >= 5 then
                                self:SetChecked(false)
                                return
                            end
                            cc.socialGrs[self.colKey] = true
                        else
                            cc.socialGrs[self.colKey] = false
                        end
                        UpdateSocialGrsCounter()
                    end
                end
                UpdateSocialGrsCounter()

                -- Apply button
                local socialApplyBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
                socialApplyBtn:SetSize(120, 26); socialApplyBtn:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 10, 10); socialApplyBtn:SetText("Apply")
                if NS.SkinButton then NS.SkinButton(socialApplyBtn) end
                if self.db.guildMode ~= "social" then socialApplyBtn:Disable() end
                local socialAppliedLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                socialAppliedLabel:SetPoint("LEFT", socialApplyBtn, "RIGHT", 10, 0); socialAppliedLabel:SetText("|cff00ff00Settings applied|r"); socialAppliedLabel:Hide()
                socialApplyBtn:SetScript("OnClick", function()
                    -- Rebuild Guild Roster
                    if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {} end
                    if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end
                    if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
                    if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
                    if GR.UpdateRosterList then GR:UpdateRosterList() end

                    -- Rebuild GRS center pane
                    local cp = _G["GRS_CenterPane"]
                    if cp then
                        local kids = { cp:GetChildren() }
                        for _, child in ipairs(kids) do child:Hide(); child:SetParent(nil) end
                        local regions = { cp:GetRegions() }
                        for _, r in ipairs(regions) do r:Hide(); r:SetParent(nil) end
                        GR.ResultsHeader = nil; GR.SearchBtn = nil; GR.StatusText = nil
                        GR.grsVisibleCols = nil
                        GR:BuildCenterPane(cp)
                        if GR.UpdateHomeLayout then GR.UpdateHomeLayout() end
                    end
                    socialAppliedLabel:Show()
                    C_Timer.After(3, function() if socialAppliedLabel then socialAppliedLabel:Hide() end end)
                end)
                modeApplyBtns["social"] = socialApplyBtn
            end

            -- =============================================================
            -- RAID GUILD MODE: GRS Column Configuration
            -- =============================================================
            if mode.key == "raid" then
                local cc = self.db.customColumns

                local function CountEnabledRaid(tbl)
                    local n = 0
                    for _, v in pairs(tbl) do if v then n = n + 1 end end
                    return n
                end

                local raidGrsTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                raidGrsTitle:SetPoint("TOPLEFT", 10, -50); raidGrsTitle:SetText("GRS Columns (max 5)"); raidGrsTitle:SetTextColor(1, 0.82, 0)
                local raidGrsCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                raidGrsCounter:SetPoint("LEFT", raidGrsTitle, "RIGHT", 10, 0); raidGrsCounter:SetTextColor(0.7, 0.7, 0.7)

                local RGRS_COLS = {
                    { key = "zone",   label = "Zone" },
                    { key = "maxKey", label = "M+ (Max Key)" },
                    { key = "rio",    label = "Score" },
                    { key = "raidN",  label = "Normal" },
                    { key = "heroic", label = "Heroic" },
                    { key = "mythic", label = "Mythic" },
                    { key = "warbandScore", label = "Warband Score" },
                }
                local rgrsCbs = {}
                local function UpdateRaidGrsCounter()
                    raidGrsCounter:SetText(CountEnabledRaid(cc.raidGrs) .. "/5 selected")
                end
                local rgrsCols = 3; local rgrsStartY = -70; local rgrsStartX = 10; local rgrsColW = 180; local rgrsRowH = 28
                for idx, col in ipairs(RGRS_COLS) do
                    local colIdx = (idx - 1) % rgrsCols; local rowIdx = math.floor((idx - 1) / rgrsCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, rgrsStartX + (colIdx * rgrsColW), rgrsStartY - (rowIdx * rgrsRowH))
                    cb:SetChecked(cc.raidGrs[col.key] ~= false)
                    cb.colKey = col.key
                    rgrsCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabledRaid(cc.raidGrs) >= 5 then
                                self:SetChecked(false)
                                return
                            end
                            cc.raidGrs[self.colKey] = true
                        else
                            cc.raidGrs[self.colKey] = false
                        end
                        UpdateRaidGrsCounter()
                    end
                end
                UpdateRaidGrsCounter()

                local raidApplyBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
                raidApplyBtn:SetSize(120, 26); raidApplyBtn:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 10, 10); raidApplyBtn:SetText("Apply")
                if NS.SkinButton then NS.SkinButton(raidApplyBtn) end
                if self.db.guildMode ~= "raid" then raidApplyBtn:Disable() end
                local raidAppliedLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                raidAppliedLabel:SetPoint("LEFT", raidApplyBtn, "RIGHT", 10, 0); raidAppliedLabel:SetText("|cff00ff00Settings applied|r"); raidAppliedLabel:Hide()
                raidApplyBtn:SetScript("OnClick", function()
                    if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {} end
                    if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end
                    if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
                    if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
                    if GR.UpdateRosterList then GR:UpdateRosterList() end
                    local cp = _G["GRS_CenterPane"]
                    if cp then
                        local kids = { cp:GetChildren() }
                        for _, child in ipairs(kids) do child:Hide(); child:SetParent(nil) end
                        local regions = { cp:GetRegions() }
                        for _, r in ipairs(regions) do r:Hide(); r:SetParent(nil) end
                        GR.ResultsHeader = nil; GR.SearchBtn = nil; GR.StatusText = nil
                        GR.grsVisibleCols = nil
                        GR:BuildCenterPane(cp)
                        if GR.UpdateHomeLayout then GR.UpdateHomeLayout() end
                    end
                    raidAppliedLabel:Show()
                    C_Timer.After(3, function() if raidAppliedLabel then raidAppliedLabel:Hide() end end)
                end)
                modeApplyBtns["raid"] = raidApplyBtn
            end

            -- =============================================================
            -- M+ GUILD MODE: GRS Column Configuration
            -- =============================================================
            if mode.key == "mplus" then
                local cc = self.db.customColumns

                local function CountEnabledMplus(tbl)
                    local n = 0
                    for _, v in pairs(tbl) do if v then n = n + 1 end end
                    return n
                end

                local mplusGrsTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                mplusGrsTitle:SetPoint("TOPLEFT", 10, -50); mplusGrsTitle:SetText("GRS Columns (max 5)"); mplusGrsTitle:SetTextColor(1, 0.82, 0)
                local mplusGrsCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                mplusGrsCounter:SetPoint("LEFT", mplusGrsTitle, "RIGHT", 10, 0); mplusGrsCounter:SetTextColor(0.7, 0.7, 0.7)

                local MGRS_COLS = {
                    { key = "zone",   label = "Zone" },
                    { key = "maxKey", label = "M+ (Max Key)" },
                    { key = "rio",    label = "Score" },
                    { key = "raidN",  label = "Normal" },
                    { key = "heroic", label = "Heroic" },
                    { key = "mythic", label = "Mythic" },
                    { key = "warbandScore", label = "Warband Score" },
                }
                local mgrsCbs = {}
                local function UpdateMplusGrsCounter()
                    mplusGrsCounter:SetText(CountEnabledMplus(cc.mplusGrs) .. "/5 selected")
                end
                local mgrsCols = 3; local mgrsStartY = -70; local mgrsStartX = 10; local mgrsColW = 180; local mgrsRowH = 28
                for idx, col in ipairs(MGRS_COLS) do
                    local colIdx = (idx - 1) % mgrsCols; local rowIdx = math.floor((idx - 1) / mgrsCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, mgrsStartX + (colIdx * mgrsColW), mgrsStartY - (rowIdx * mgrsRowH))
                    cb:SetChecked(cc.mplusGrs[col.key] ~= false)
                    cb.colKey = col.key
                    mgrsCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabledMplus(cc.mplusGrs) >= 5 then
                                self:SetChecked(false)
                                return
                            end
                            cc.mplusGrs[self.colKey] = true
                        else
                            cc.mplusGrs[self.colKey] = false
                        end
                        UpdateMplusGrsCounter()
                    end
                end
                UpdateMplusGrsCounter()

                local mplusApplyBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
                mplusApplyBtn:SetSize(120, 26); mplusApplyBtn:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 10, 10); mplusApplyBtn:SetText("Apply")
                if NS.SkinButton then NS.SkinButton(mplusApplyBtn) end
                if self.db.guildMode ~= "mplus" then mplusApplyBtn:Disable() end
                local mplusAppliedLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                mplusAppliedLabel:SetPoint("LEFT", mplusApplyBtn, "RIGHT", 10, 0); mplusAppliedLabel:SetText("|cff00ff00Settings applied|r"); mplusAppliedLabel:Hide()
                mplusApplyBtn:SetScript("OnClick", function()
                    if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {} end
                    if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end
                    if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
                    if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
                    if GR.UpdateRosterList then GR:UpdateRosterList() end
                    local cp = _G["GRS_CenterPane"]
                    if cp then
                        local kids = { cp:GetChildren() }
                        for _, child in ipairs(kids) do child:Hide(); child:SetParent(nil) end
                        local regions = { cp:GetRegions() }
                        for _, r in ipairs(regions) do r:Hide(); r:SetParent(nil) end
                        GR.ResultsHeader = nil; GR.SearchBtn = nil; GR.StatusText = nil
                        GR.grsVisibleCols = nil
                        GR:BuildCenterPane(cp)
                        if GR.UpdateHomeLayout then GR.UpdateHomeLayout() end
                    end
                    mplusAppliedLabel:Show()
                    C_Timer.After(3, function() if mplusAppliedLabel then mplusAppliedLabel:Hide() end end)
                end)
                modeApplyBtns["mplus"] = mplusApplyBtn
            end

            -- =============================================================
            -- PVP GUILD MODE: Guild Roster Column Configuration
            -- =============================================================
            if mode.key == "pvp" then
                local cc = self.db.customColumns

                local function CountEnabledPvp(tbl)
                    local n = 0
                    for _, v in pairs(tbl) do if v then n = n + 1 end end
                    return n
                end

                -- ---- Guild Roster Columns (max 6 of 7) ----
                local pvpRosterTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                pvpRosterTitle:SetPoint("TOPLEFT", 10, -50); pvpRosterTitle:SetText("Guild Roster Columns (max 6)"); pvpRosterTitle:SetTextColor(1, 0.82, 0)
                local pvpRosterCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                pvpRosterCounter:SetPoint("LEFT", pvpRosterTitle, "RIGHT", 10, 0); pvpRosterCounter:SetTextColor(0.7, 0.7, 0.7)

                local PROSTER_COLS = {
                    { key = "pvp2v2",  label = "2v2 Rating" },
                    { key = "pvp3v3",  label = "3v3 Rating" },
                    { key = "pvpSolo", label = "Solo Shuffle" },
                    { key = "pvpRbg",  label = "RBG Rating" },
                    { key = "pvpBest", label = "Best Rating" },
                    { key = "pvpExp",  label = "Experience" },
                    { key = "pvpSpec", label = "Spec" },
                }
                local prosterCbs = {}
                local function UpdatePvpRosterCounter()
                    pvpRosterCounter:SetText(CountEnabledPvp(cc.pvpRoster) .. "/6 selected")
                end
                local prCols = 4; local prStartY = -70; local prStartX = 10; local prColW = 155; local prRowH = 28
                for idx, col in ipairs(PROSTER_COLS) do
                    local colIdx = (idx - 1) % prCols; local rowIdx = math.floor((idx - 1) / prCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, prStartX + (colIdx * prColW), prStartY - (rowIdx * prRowH))
                    cb:SetChecked(cc.pvpRoster[col.key] ~= false)
                    cb.colKey = col.key
                    prosterCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabledPvp(cc.pvpRoster) >= 6 then
                                self:SetChecked(false)
                                return
                            end
                            cc.pvpRoster[self.colKey] = true
                        else
                            cc.pvpRoster[self.colKey] = false
                        end
                        UpdatePvpRosterCounter()
                    end
                end
                UpdatePvpRosterCounter()

                local pvpApplyBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
                pvpApplyBtn:SetSize(120, 26); pvpApplyBtn:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 10, 10); pvpApplyBtn:SetText("Apply")
                if NS.SkinButton then NS.SkinButton(pvpApplyBtn) end
                if self.db.guildMode ~= "pvp" then pvpApplyBtn:Disable() end
                local pvpAppliedLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                pvpAppliedLabel:SetPoint("LEFT", pvpApplyBtn, "RIGHT", 10, 0); pvpAppliedLabel:SetText("|cff00ff00Settings applied|r"); pvpAppliedLabel:Hide()
                pvpApplyBtn:SetScript("OnClick", function()
                    if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {} end
                    if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end
                    if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
                    if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
                    if GR.UpdateRosterList then GR:UpdateRosterList() end
                    pvpAppliedLabel:Show()
                    C_Timer.After(3, function() if pvpAppliedLabel then pvpAppliedLabel:Hide() end end)
                end)
                modeApplyBtns["pvp"] = pvpApplyBtn
            end

            -- =============================================================
            -- CUSTOM GUILD MODE: Column Configuration Tables
            -- =============================================================
            if mode.key == "custom" then
                local cc = self.db.customColumns

                -- Helper: count enabled columns
                local function CountEnabled(tbl)
                    local n = 0
                    for _, v in pairs(tbl) do if v then n = n + 1 end end
                    return n
                end

                -- ---- GRS Columns (max 5 of 6) ----
                local grsTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                grsTitle:SetPoint("TOPLEFT", 10, -50); grsTitle:SetText("GRS Columns (max 5)"); grsTitle:SetTextColor(1, 0.82, 0)
                local grsCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                grsCounter:SetPoint("LEFT", grsTitle, "RIGHT", 10, 0); grsCounter:SetTextColor(0.7, 0.7, 0.7)

                local GRS_COLS = {
                    { key = "zone",   label = "Zone" },
                    { key = "maxKey", label = "M+ (Max Key)" },
                    { key = "rio",    label = "Score" },
                    { key = "raidN",  label = "Normal" },
                    { key = "heroic", label = "Heroic" },
                    { key = "mythic", label = "Mythic" },
                    { key = "warbandScore", label = "Warband Score" },
                }
                local grsCbs = {}
                local function UpdateGrsCounter()
                    grsCounter:SetText(CountEnabled(cc.grs) .. "/5 selected")
                end
                local grsCols = 3; local grsStartY = -70; local grsStartX = 10; local grsColW = 180; local grsRowH = 28
                for idx, col in ipairs(GRS_COLS) do
                    local colIdx = (idx - 1) % grsCols; local rowIdx = math.floor((idx - 1) / grsCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, grsStartX + (colIdx * grsColW), grsStartY - (rowIdx * grsRowH))
                    cb:SetChecked(cc.grs[col.key] ~= false)
                    cb.colKey = col.key
                    grsCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabled(cc.grs) >= 5 then
                                self:SetChecked(false)
                                return
                            end
                            cc.grs[self.colKey] = true
                        else
                            cc.grs[self.colKey] = false
                        end
                        UpdateGrsCounter()
                    end
                end
                UpdateGrsCounter()

                -- ---- Guild Roster Columns (max 6 of 7) ----
                local rosterTitle = pane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                rosterTitle:SetPoint("TOPLEFT", 10, -170); rosterTitle:SetText("Guild Roster Columns (max 6)"); rosterTitle:SetTextColor(1, 0.82, 0)
                local rosterCounter = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                rosterCounter:SetPoint("LEFT", rosterTitle, "RIGHT", 10, 0); rosterCounter:SetTextColor(0.7, 0.7, 0.7)

                local ROSTER_COLS = {
                    { key = "ach",   label = "Achievement" },
                    { key = "ilvl",  label = "ilvl" },
                    { key = "rio",   label = "M+ Score" },
                    { key = "raidN", label = "N (Normal)" },
                    { key = "raidH", label = "H (Heroic)" },
                    { key = "raidM", label = "M (Mythic)" },
                    { key = "maxKey", label = "Max Key" },
                }
                local rosterCbs = {}
                local function UpdateRosterCounter()
                    rosterCounter:SetText(CountEnabled(cc.roster) .. "/6 selected")
                end
                local rCols = 4; local rStartY = -190; local rStartX = 10; local rColW = 155; local rRowH = 28
                for idx, col in ipairs(ROSTER_COLS) do
                    local colIdx = (idx - 1) % rCols; local rowIdx = math.floor((idx - 1) / rCols)
                    local cb = CreateStyledCheckbox(pane, col.label, "TOPLEFT", nil, nil, rStartX + (colIdx * rColW), rStartY - (rowIdx * rRowH))
                    cb:SetChecked(cc.roster[col.key] ~= false)
                    cb.colKey = col.key
                    rosterCbs[col.key] = cb
                    cb.onClickHandler = function(self)
                        if self:GetChecked() then
                            if CountEnabled(cc.roster) >= 6 then
                                self:SetChecked(false)
                                return
                            end
                            cc.roster[self.colKey] = true
                        else
                            cc.roster[self.colKey] = false
                        end
                        UpdateRosterCounter()
                    end
                end
                UpdateRosterCounter()

                -- Apply button
                local applyBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
                applyBtn:SetSize(120, 26); applyBtn:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 10, 10); applyBtn:SetText("Apply")
                if NS.SkinButton then NS.SkinButton(applyBtn) end
                if self.db.guildMode ~= "custom" then applyBtn:Disable() end
                local customAppliedLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                customAppliedLabel:SetPoint("LEFT", applyBtn, "RIGHT", 10, 0); customAppliedLabel:SetText("|cff00ff00Settings applied|r"); customAppliedLabel:Hide()
                applyBtn:SetScript("OnClick", function()
                    -- Rebuild Guild Roster
                    if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {} end
                    if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end
                    if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
                    if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
                    if GR.UpdateRosterList then GR:UpdateRosterList() end

                    -- Rebuild GRS center pane
                    local cp = _G["GRS_CenterPane"]
                    if cp then
                        local kids = { cp:GetChildren() }
                        for _, child in ipairs(kids) do child:Hide(); child:SetParent(nil) end
                        local regions = { cp:GetRegions() }
                        for _, r in ipairs(regions) do r:Hide(); r:SetParent(nil) end
                        GR.ResultsHeader = nil; GR.SearchBtn = nil; GR.StatusText = nil
                        GR.grsVisibleCols = nil
                        GR:BuildCenterPane(cp)
                        if GR.UpdateHomeLayout then GR.UpdateHomeLayout() end
                    end
                    customAppliedLabel:Show()
                    C_Timer.After(3, function() if customAppliedLabel then customAppliedLabel:Hide() end end)
                end)
                modeApplyBtns["custom"] = applyBtn
            end

            if mode.key == "custom" then y = y - 385 elseif mode.key == "social" or mode.key == "raid" or mode.key == "mplus" or mode.key == "pvp" then y = y - 285 else y = y - 75 end
        end
        c:SetHeight(math.abs(y) + 20)
    end

    -- =================================================================
    -- PAGE 3: APPEARANCES
    -- =================================================================
    do
        local c = pages[3].canvas; local y = -10

        -- Transparency & Contrast (height +25, gap +10)
        local p1 = CreateOptionPane(c, y, NS.L["TRANSPARENCY_CONTRAST"] or "Transparency & Contrast", "Panel opacity with a high-contrast text option.", 105)
        local alphaS = CreateColorSlider(p1, "Background Alpha", function() return GR.db.theme.background.a end, function(v) GR.db.theme.background.a = v; UpdateLiveTheme() end)
        alphaS:SetPoint("TOPLEFT", 10, -55); alphaS:SetWidth(300)
        y = y - 110

        -- UI Scale
        local p2 = CreateOptionPane(c, y, NS.L["UI_SCALE"] or "UI Scale", "Adjust overall addon UI scale. Values between 0.60 and 1.40.", 80)
        local valScale = p2:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); valScale:SetPoint("TOPRIGHT", -10, -10); valScale:SetText(string.format("%.2f", self.db.scale or 1.0))
        local sliderScale = CreateFrame("Slider", "GRS_ScaleSlider", p2, "OptionsSliderTemplate"); sliderScale:SetPoint("TOPLEFT", 10, -50); 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)
        y = y - 85

        -- =============================================================
        -- Theme and Colors: Unified horizontal pane with presets
        -- =============================================================
        local themePane = CreateOptionPane(c, y, "Theme and Colors", "Adjust header, background and button colors. Or pick a preset.", 310)

        local colSliders = {}
        local function MakeColorColumn(cparent, xOffset, colTitle, dbKey, useAlpha)
            local col = CreateFrame("Frame", nil, cparent); col:SetSize(210, 200)
            col:SetPoint("TOPLEFT", xOffset, -42)
            local hdr = col:CreateFontString(nil, "OVERLAY", "GameFontNormal"); hdr:SetPoint("TOP", 0, 0); hdr:SetText(colTitle); hdr:SetTextColor(1, 0.82, 0)
            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 sliders = {}
            local rS = CreateColorSlider(col, "Red", function() return GetCol("r") end, function(v) SetCol("r", v) end); rS:SetPoint("TOPLEFT", 5, -25); rS:SetWidth(195); sliders.r = rS
            local gS = CreateColorSlider(col, "Green", function() return GetCol("g") end, function(v) SetCol("g", v) end); gS:SetPoint("TOPLEFT", 5, -60); gS:SetWidth(195); sliders.g = gS
            local bS = CreateColorSlider(col, "Blue", function() return GetCol("b") end, function(v) SetCol("b", v) end); bS:SetPoint("TOPLEFT", 5, -95); bS:SetWidth(195); sliders.b = bS
            if useAlpha then
                local aS = CreateColorSlider(col, "Alpha", function() return GetCol("a") end, function(v) SetCol("a", v) end); aS:SetPoint("TOPLEFT", 5, -130); aS:SetWidth(195); sliders.a = aS
            else
                if GR.db.theme[dbKey] then GR.db.theme[dbKey].a = 1 end
            end
            colSliders[dbKey] = sliders
            return col
        end
        MakeColorColumn(themePane, 10,  "Header / Sidebar",  "header",     false)
        MakeColorColumn(themePane, 225, "Background Pane",   "background", true)
        MakeColorColumn(themePane, 440, "Buttons & Text",    "buttons",    false)

        -- Preset Definitions (8 presets)
        local PRESETS = {
            { name = "Default",     header = {r=0.10, g=0.10, b=0.20}, background = {r=0.05, g=0.05, b=0.05, a=0.95}, buttons = {r=0.20, g=0.20, b=0.20} },
            { name = "Obsidian",    header = {r=0.06, g=0.06, b=0.06}, background = {r=0.03, g=0.03, b=0.03, a=0.98}, buttons = {r=0.12, g=0.12, b=0.12} },
            { name = "Arcane",      header = {r=0.18, g=0.05, b=0.30}, background = {r=0.06, g=0.02, b=0.12, a=0.95}, buttons = {r=0.25, g=0.08, b=0.40} },
            { name = "Destruction", header = {r=0.35, g=0.05, b=0.02}, background = {r=0.10, g=0.02, b=0.01, a=0.95}, buttons = {r=0.45, g=0.10, b=0.05} },
            { name = "Healer",     header = {r=0.02, g=0.20, b=0.10}, background = {r=0.01, g=0.08, b=0.04, a=0.95}, buttons = {r=0.05, g=0.28, b=0.14} },
            { name = "Protector",  header = {r=0.08, g=0.15, b=0.28}, background = {r=0.03, g=0.06, b=0.12, a=0.95}, buttons = {r=0.12, g=0.22, b=0.35} },
            { name = "Crusader",   header = {r=0.30, g=0.22, b=0.05}, background = {r=0.10, g=0.07, b=0.02, a=0.95}, buttons = {r=0.40, g=0.30, b=0.08} },
            { name = "Iron Man",   header = {r=0.55, g=0.08, b=0.08}, background = {r=0.12, g=0.04, b=0.02, a=0.96}, buttons = {r=0.65, g=0.45, b=0.05} },
        }

        local function ApplyPreset(preset)
            for _, dbKey in ipairs({"header", "background", "buttons"}) do
                local src = preset[dbKey]
                if src and GR.db.theme[dbKey] then
                    for k, v in pairs(src) do GR.db.theme[dbKey][k] = v end
                    if not src.a then GR.db.theme[dbKey].a = 1 end
                    if colSliders[dbKey] then
                        for ck, slider in pairs(colSliders[dbKey]) do
                            local val = GR.db.theme[dbKey][ck]
                            if val then slider:SetValue(val) end
                        end
                    end
                end
            end
            UpdateLiveTheme()
        end

        -- Preset buttons (2x4 grid)
        local presetY = -205; local presetX = 10; local presetCols = 4; local presetBtnW = 150; local presetBtnH = 28; local presetPadX = 8; local presetPadY = 6
        local presetLabel = themePane:CreateFontString(nil, "OVERLAY", "GameFontNormal"); presetLabel:SetPoint("TOPLEFT", 10, -192); presetLabel:SetText("Presets:"); presetLabel:SetTextColor(0.8, 0.8, 0.8)
        for idx, preset in ipairs(PRESETS) do
            local col = (idx - 1) % presetCols; local row = math.floor((idx - 1) / presetCols)
            local btn = CreateFrame("Button", nil, themePane)
            btn:SetSize(presetBtnW, presetBtnH); btn:SetPoint("TOPLEFT", presetX + col * (presetBtnW + presetPadX), presetY - row * (presetBtnH + presetPadY))
            btn:SetNormalTexture(""); btn:SetHighlightTexture(""); btn:SetPushedTexture("")
            local swatch = btn:CreateTexture(nil, "ARTWORK"); swatch:SetSize(6, presetBtnH - 4); swatch:SetPoint("LEFT", 2, 0)
            swatch:SetColorTexture(preset.header.r, preset.header.g, preset.header.b, 1)
            local bg = btn:CreateTexture(nil, "BORDER"); bg:SetAllPoints(); bg:SetColorTexture(0, 0, 0, 1); btn.bg = bg
            local brd = btn:CreateTexture(nil, "BACKGROUND"); brd:SetPoint("TOPLEFT", -1, 1); brd:SetPoint("BOTTOMRIGHT", 1, -1); brd:SetColorTexture(0.25, 0.25, 0.25, 1); btn.brd = brd
            local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); txt:SetPoint("CENTER", 4, 0); txt:SetText(preset.name); txt:SetTextColor(1, 1, 1)
            btn:SetScript("OnEnter", function(s) s.bg:SetColorTexture(0.15, 0.15, 0.15, 1) end)
            btn:SetScript("OnLeave", function(s) s.bg:SetColorTexture(0, 0, 0, 1) end)
            btn:SetScript("OnClick", function() ApplyPreset(preset) end)
        end
        y = y - 315

        -- Compact Mode (checkbox in front of name)
        local p6 = CreateOptionPane(c, y, NS.L["COMPACT_MODE"] or "Compact Mode", "Enable a compact layout mode for the addon interface.", 70)
        local chkCompact = CreateStyledCheckbox(p6, nil, "TOPLEFT", nil, nil, 10, -8)
        chkCompact:SetChecked(self.db.compactMode or false)
        p6.title:ClearAllPoints(); p6.title:SetPoint("TOPLEFT", 38, -8)
        if p6.desc then p6.desc:ClearAllPoints(); p6.desc:SetPoint("TOPLEFT", 38, -26); p6.desc:SetPoint("RIGHT", p6, "RIGHT", -10, 0) end
        chkCompact.onClickHandler = function(cb) GR.db.compactMode = cb:GetChecked(); if GR.ToggleCompactMode then GR:ToggleCompactMode(GR.db.compactMode) end end
        y = y - 75

        -- Custom Background + Reload UI (MERGED, +50px height)
        local p7 = CreateOptionPane(c, y, NS.L["CUSTOM_BACKGROUND"] or "Custom Background & Reload", "Enable and configure custom background images per tab.", 440)
        if not self.db.customBackgrounds then self.db.customBackgrounds = {} end
        local chkEnableBg = CreateStyledCheckbox(p7, NS.L["ENABLE_CUSTOM_BG"] or "Enable Custom Background", "TOPLEFT", nil, nil, 10, -45)
        chkEnableBg:SetChecked(self.db.customBackgrounds.enabled or false)

        -- Set Directory (left side)
        local lblDir = p7:CreateFontString(nil, "OVERLAY", "GameFontNormal"); lblDir:SetPoint("TOPLEFT", 10, -75); lblDir:SetText(NS.L["SET_DIRECTORY"] or "Set directory")
        local edtDir = CreateFrame("EditBox", nil, p7, "InputBoxTemplate"); edtDir:SetSize(280, 20); edtDir:SetPoint("TOPLEFT", 10, -95); edtDir:SetAutoFocus(false); edtDir:SetFontObject("ChatFontSmall"); edtDir:SetText(self.db.customBackgrounds.directory or "Interface\\AddOns\\GuildRecruiterManagement\\Media")
        local btnDir = CreateFrame("Button", nil, p7, "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)

        -- Reload UI button (below Set Directory, 50px gap)
        local btnReload = CreateFrame("Button", nil, p7, "UIPanelButtonTemplate"); btnReload:SetSize(120, 25); btnReload:SetPoint("TOPLEFT", 10, -165); btnReload:SetText(NS.L["RELOAD_UI"] or "Reload UI"); btnReload:SetScript("OnClick", function() C_UI.Reload() end); SafeSkinButton(btnReload)
        local txtReload = p7:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); txtReload:SetPoint("LEFT", btnReload, "RIGHT", 10, 0); txtReload:SetText(NS.L["RELOAD_UI_NOTE"] or "Reload UI for scale and theme changes to take full effect."); txtReload:SetTextColor(0.6, 0.6, 0.6)

        -- Background file inputs (right column, with title)
        local bgTitle = p7:CreateFontString(nil, "OVERLAY", "GameFontNormal"); bgTitle:SetPoint("TOPLEFT", 360, -45); bgTitle:SetText("Tab Backgrounds"); bgTitle:SetTextColor(1, 0.82, 0)
        local function CreateBgRow(rParent, index, labelText, defaultFile, ryOffset)
            local label = rParent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); label:SetPoint("TOPLEFT", 360, ryOffset); label:SetText(labelText)
            local edit = CreateFrame("EditBox", nil, rParent, "InputBoxTemplate"); edit:SetSize(230, 18); edit:SetPoint("TOPLEFT", 360, ryOffset - 14); edit:SetAutoFocus(false); edit:SetFontObject("ChatFontSmall")
            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, rParent, "UIPanelButtonTemplate"); btn:SetSize(35, 18); btn:SetPoint("LEFT", edit, "RIGHT", 3, 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 bgY = -65
        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); CreateBgRow(p7, i, title, nil, bgY); bgY = bgY - 38 end end
        CreateBgRow(p7, "GuildChat", "Guild Chat", "Background_G-chat.tga", bgY)

        local function ToggleCustomControls(enable) local alpha = enable and 1 or 0.5; edtDir:SetAlpha(alpha); btnDir:SetAlpha(alpha) end
        chkEnableBg.onClickHandler = function(cb) GR.db.customBackgrounds.enabled = cb:GetChecked(); ToggleCustomControls(GR.db.customBackgrounds.enabled) end
        ToggleCustomControls(self.db.customBackgrounds.enabled)
        y = y - 445

        c:SetHeight(math.abs(y) + 20)
    end

    -- =================================================================
    -- PAGE 4: TOOLS (checkboxes in front)
    -- =================================================================
    do
        local c = pages[4].canvas; local y = -10
        local p1 = CreateOptionPane(c, y, NS.L["ENABLE_MACRO_TOOLS"] or "Macro Tools", "Enable the Macro Tools panel for advanced recruitment macros and automation.", 70)
        local chkMacro = CreateStyledCheckbox(p1, nil, "TOPLEFT", nil, nil, 10, -8)
        p1.title:ClearAllPoints(); p1.title:SetPoint("TOPLEFT", 38, -8)
        if p1.desc then p1.desc:ClearAllPoints(); p1.desc:SetPoint("TOPLEFT", 38, -26); p1.desc:SetPoint("RIGHT", p1, "RIGHT", -10, 0) end
        if DB_Rmap_Tools and DB_Rmap_Tools.settings then chkMacro:SetChecked(DB_Rmap_Tools.settings.isMacroPanelOpen) else chkMacro:SetChecked(false) end
        chkMacro.onClickHandler = function(cb)
            local isEnabled = cb: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
        y = y - 75
        c:SetHeight(math.abs(y) + 20)
    end

    -- =================================================================
    -- PAGE 5: LANGUAGE (fixed encoding, styled checkboxes)
    -- =================================================================
    do
        local c = pages[5].canvas; local y = -10
        local p1 = CreateOptionPane(c, y, NS.L["LANGUAGE"] or "Language", "Select the display language for the addon interface. Requires a UI reload to apply.", 280)
        if not self.db.selectedLanguage then self.db.selectedLanguage = nil end
        local LANGUAGES = {
            { key = "enUS", label = "English" },
            { key = "deDE", label = "Deutsch" },
            { key = "esES", label = "Espa\195\177ol (EU)" },
            { key = "frFR", label = "Fran\195\167ais" },
            { key = "itIT", label = "Italiano" },
            { key = "ruRU", label = "\208\160\209\131\209\129\209\129\208\186\208\184\208\185" },
            { key = "esMX", label = "Espa\195\177ol (AL)" },
            { key = "ptBR", label = "Portugu\195\170s" },
            { key = "koKR", label = "\237\149\156\234\181\173\236\150\180" },
            { key = "zhCN", label = "\231\174\128\228\189\147\228\184\173\230\150\135" },
            { key = "zhTW", label = "\231\185\129\233\171\148\228\184\173\230\150\135" },
        }
        local langCheckboxes = {}
        local cols = 4; local colWidth = 170; local rowHeight = 30; local startY = -45; local startX = 10
        for idx, lang in ipairs(LANGUAGES) do
            local col = (idx - 1) % cols; local row = math.floor((idx - 1) / cols)
            local chkLang = CreateStyledCheckbox(p1, lang.label, "TOPLEFT", nil, nil, startX + (col * colWidth), startY - (row * rowHeight))
            chkLang:SetChecked(self.db.selectedLanguage == lang.key)
            chkLang.langKey = lang.key; langCheckboxes[lang.key] = chkLang
            chkLang.onClickHandler = function(cb)
                if cb:GetChecked() then
                    GR.db.selectedLanguage = cb.langKey
                    for key, otherCb in pairs(langCheckboxes) do if key ~= cb.langKey then otherCb:SetChecked(false) end end
                else
                    GR.db.selectedLanguage = nil
                end
            end
        end
        -- Apply Language Button
        local btnApplyLang = CreateFrame("Button", nil, p1, "UIPanelButtonTemplate"); btnApplyLang:SetSize(140, 30); btnApplyLang:SetPoint("TOPLEFT", startX, startY - (math.ceil(#LANGUAGES / cols) * rowHeight) - 10)
        btnApplyLang:SetText(NS.L["APPLY_LANGUAGE"] or "Apply Language"); SafeSkinButton(btnApplyLang)
        btnApplyLang:SetScript("OnClick", function()
            local lang = GR.db.selectedLanguage
            if lang then ReloadUI() end
        end)
        y = y - 285
        c:SetHeight(math.abs(y) + 20)
    end

    -- =================================================================
    -- PAGE 6: ADVANCED (checkboxes in front, merged import/export)
    -- =================================================================
    do
        local c = pages[6].canvas; local y = -10

        -- Advanced Character Inspection (checkbox in front)
        local p1 = CreateOptionPane(c, y, NS.L["ADVANCED_INSPECTION"] or "Advanced Character Inspection", "Enable or disable the advanced character inspection and armory system. Default is OFF.", 70)
        local chkInspect = CreateStyledCheckbox(p1, nil, "TOPLEFT", nil, nil, 10, -8)
        p1.title:ClearAllPoints(); p1.title:SetPoint("TOPLEFT", 38, -8)
        if p1.desc then p1.desc:ClearAllPoints(); p1.desc:SetPoint("TOPLEFT", 38, -26); p1.desc:SetPoint("RIGHT", p1, "RIGHT", -10, 0) end
        chkInspect:SetChecked(self.db.disableInspect == false)
        chkInspect.onClickHandler = function(cb)
            local isEnabled = cb:GetChecked(); GR.db.disableInspect = not isEnabled
            if _G.AXIOM_Armory_Frame_Reboot and _G.AXIOM_Armory_Frame_Reboot.ToggleSystem then _G.AXIOM_Armory_Frame_Reboot:ToggleSystem(isEnabled) end
            if _G.AXIOM_Target_Inspect_Frame and _G.AXIOM_Target_Inspect_Frame.ToggleSystem then _G.AXIOM_Target_Inspect_Frame:ToggleSystem(isEnabled) end
        end
        C_Timer.After(1, function()
            local isEnabled = (GR.db.disableInspect == false)
            if _G.AXIOM_Armory_Frame_Reboot and _G.AXIOM_Armory_Frame_Reboot.ToggleSystem then _G.AXIOM_Armory_Frame_Reboot:ToggleSystem(isEnabled) end
            if _G.AXIOM_Target_Inspect_Frame and _G.AXIOM_Target_Inspect_Frame.ToggleSystem then _G.AXIOM_Target_Inspect_Frame:ToggleSystem(isEnabled) end
        end)
        y = y - 75

        -- Advanced Guild Roster (checkbox in front)
        local p2 = CreateOptionPane(c, y, NS.L["DISABLE_ADVANCED_ROSTER"] or "Advanced Guild Roster", NS.L["DISABLE_ADVANCED_ROSTER_NOTE"] or "Hides M+ Score, Raid Progress (N/H/M), and Max Key columns from the Guild Roster.", 70)
        local chkAdvanced = CreateStyledCheckbox(p2, nil, "TOPLEFT", nil, nil, 10, -8)
        p2.title:ClearAllPoints(); p2.title:SetPoint("TOPLEFT", 38, -8)
        if p2.desc then p2.desc:ClearAllPoints(); p2.desc:SetPoint("TOPLEFT", 38, -26); p2.desc:SetPoint("RIGHT", p2, "RIGHT", -10, 0) end
        chkAdvanced:SetChecked(self.db.disableAdvancedRoster or false)
        chkAdvanced.onClickHandler = function(cb)
            GR.db.disableAdvancedRoster = cb:GetChecked()
            if GR.RosterSplitMain then GR.RosterSplitMain:Hide(); GR.RosterSplitMain = nil; GR.RosterRows = {}; GR.Rows = {}; if GR.RosterContent then GR.RosterContent:Hide(); GR.RosterContent = nil end end
            if GR.RightPaneTop then GR.RightPaneTop:Hide(); GR.RightPaneTop = nil end
            if GR.RightPaneBottom then GR.RightPaneBottom:Hide(); GR.RightPaneBottom = nil end
            if GR.UpdateRosterList then GR:UpdateRosterList() end
        end
        y = y - 75

        -- Import / Export (MERGED into single pane, buttons side-by-side)
        local p3 = CreateOptionPane(c, y, "Import / Export", "Import or export guild member data via the Guild Roster Manager format.", 70)
        local btnImport = CreateFrame("Button", nil, p3, "UIPanelButtonTemplate"); btnImport:SetSize(180, 28); btnImport:SetPoint("TOPLEFT", 10, -38); btnImport:SetText(NS.L["IMPORT_FROM_GRM"] or "Import from GRM"); SafeSkinButton(btnImport)
        btnImport:SetScript("OnClick", function() GR:OpenGuildImportPopup("IMPORT") end)
        local btnExport = CreateFrame("Button", nil, p3, "UIPanelButtonTemplate"); btnExport:SetSize(180, 28); btnExport:SetPoint("LEFT", btnImport, "RIGHT", 10, 0); btnExport:SetText("Export to GRM"); SafeSkinButton(btnExport)
        btnExport:SetScript("OnClick", function() GR:OpenGuildImportPopup("EXPORT") end)
        y = y - 75

        -- Bypass Filter (checkbox in front)
        local p4 = CreateOptionPane(c, y, NS.L["BYPASS_FILTER"] or "Bypass Class Rotation Filter", "Bypass the class rotation filter during recruitment scans.", 70)
        local chkBypass = CreateStyledCheckbox(p4, nil, "TOPLEFT", nil, nil, 10, -8)
        p4.title:ClearAllPoints(); p4.title:SetPoint("TOPLEFT", 38, -8)
        if p4.desc then p4.desc:ClearAllPoints(); p4.desc:SetPoint("TOPLEFT", 38, -26); p4.desc:SetPoint("RIGHT", p4, "RIGHT", -10, 0) end
        chkBypass:SetChecked(self.db.bypassFilter or false)
        chkBypass.onClickHandler = function(cb) GR.db.bypassFilter = cb:GetChecked() end
        y = y - 75

        c:SetHeight(math.abs(y) + 20)
    end

    -- Default: show General Settings page
    SelectCategory(1)
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 (Renamed)
-- =========================================================================

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()
        C_GuildInfo.GuildRoster()
        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 (Modified)
-- =========================================================================

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
    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]
        -- [[ COLUMN 5: RACE (For Faction) ]]
        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]
            
            -- [[ FACTION LOGIC: Baked In ]]
            -- Ignore imported faction (Col 19). Infer from Race (Col 5).
            if GR.DetermineFaction then
                local faction = GR:DetermineFaction(raceInput)
                GRS_IdentityDB.factions[targetKey] = faction
            end
            
            -- [[ MAIN / ALT LOGIC ]]
            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
    GR:PerformSync(true)
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, ach, aim, isMobile, isSoR, rep = 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
            if checks["MScore"] and checks["MScore"]:GetChecked() then f[18] = "0" end
            -- [[ EXPORT FACTION FROM DB ]]
            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)
        
        -- Apply Saved Inspect Setting on Init (INVERTED LOGIC FIX)
        -- disableInspect = true means DISABLED.
        -- We want Enabled if nil or false.
        -- UPDATED: Default is DISABLED (OFF). Enabled only if explicitly false.
        local isEnabled = (self.db.disableInspect == false)
        
        if _G.AXIOM_Armory_Frame_Reboot and _G.AXIOM_Armory_Frame_Reboot.ToggleSystem then
             _G.AXIOM_Armory_Frame_Reboot:ToggleSystem(isEnabled)
        end
        if _G.AXIOM_Target_Inspect_Frame and _G.AXIOM_Target_Inspect_Frame.ToggleSystem then
             _G.AXIOM_Target_Inspect_Frame:ToggleSystem(isEnabled)
        end
    end)
end)
