-- =========================================================================
-- A.X.I.O.M. ARMORY - SYSTEM RESKIN (PATCH 11.2+)
-- NATIVE FRAME OVERRIDE & VISUAL REALIGNMENT
-- =========================================================================

local addonName, NS = ...

-- Main Frame Constants
local FRAME_WIDTH = 1000 
local FRAME_HEIGHT = 500
local HEADER_HEIGHT = 30

-- Database Initialization
AXIOM_InspectDB = AXIOM_InspectDB or {}

-- System State Flag
local AXIOM_System_Enabled = true
local RESTORE_QUEUE = {}

-- Color Tokens
local COLOR_GOLD = "|cffffd100"
local COLOR_BLUE = "|cff66ccff"
local COLOR_GREEN = "|cff00ff00"
local COLOR_RED = "|cffff0000"
local COLOR_GREY = "|cff888888"
local COLOR_WHITE = "|cffffffff"

-- Specialization Color Overrides (Hex w/o |c)
local SPEC_COLORS = {
    -- MAGE
    [62]  = "ff9999ff", -- Arcane
    [63]  = "ffff5500", -- Fire
    [64]  = "ff66ccff", -- Frost
    
    -- WARLOCK
    [265] = "ff00cc00", -- Affliction
    [266] = "ff6633cc", -- Demonology
    [267] = "ffff8000", -- Destruction
}

-- Inventory Slot Mapping
local INV_SLOTS = {
    { id = 1, name = "Head" }, { id = 2, name = "Neck" }, { id = 3, name = "Shoulder" },
    { id = 15, name = "Back" }, { id = 5, name = "Chest" }, { id = 9, name = "Wrist" },
    { id = 10, name = "Hands" }, { id = 6, name = "Waist" }, { id = 7, name = "Legs" },
    { id = 8, name = "Feet" }, { id = 11, name = "Finger0" }, { id = 12, name = "Finger1" },
    { id = 13, name = "Trinket0" }, { id = 14, name = "Trinket1" }, { id = 16, name = "MainHand" },
    { id = 17, name = "SecondaryHand" }
}

-- Season 3 Dungeon Rotation (Aligned with 11.2 Meta)
local DUNGEONS = {
    { short = "GMBT", id = 0 }, { short = "EDA", id = 0 }, { short = "STRT", id = 0 }, { short = "ARAK", id = 0 },
    { short = "HOA", id = 0 }, { short = "DAWN", id = 0 }, { short = "FLOOD", id = 0 }, { short = "PSF", id = 0 }
}

-- WEAPON ENHANCEMENT DATABASE (Complete TWW + Midnight 12.x Simulation)
local WEAPON_ENHANCEMENTS = {
    -- THE WAR WITHIN (11.x)
    "Algari Mana Oil", "Oil of Beledar's Grace", "Ironclaw Whetstone", "Ironclaw Weightstone",
    "Algari Weaver's Oil", "Buzzing Rune", "Hissing Rune", "Howling Rune", "Chirping Rune",
    
    -- MIDNIGHT (12.x - Simulated Placeholders)
    "Voidfire Oil", "Sunfury Whetstone", "Ethereal Weightstone", "Luminous Mana Oil",
    
    -- LEGACY (Dragonflight / Shadowlands)
    "Shadowcore Oil", "Embalmer’s Oil", "Primal Razorstone", "Shaded Sharpening Stone", 
    "Porous Sharpening Stone", "Elemental Sharpening Stone", "Consecrated Sharpening Stone", 
    "Adamantite Sharpening Stone", "Fel Sharpening Stone", "Weightstone", "Dense Weightstone", 
    
    -- CLASS BUFFS (Poisons / Imbues)
    "Instant Poison", "Deadly Poison", "Wound Poison", "Crippling Poison", "Mind-numbing Poison", 
    "Atrophic Poison", "Amplifying Poison", -- Dragonflight Poisons
    "Windfury Weapon", "Flametongue Weapon", "Frostbrand Weapon", "Rockbiter Weapon", "Earthliving Weapon",
    
    -- PERMANENT ENCHANTS (Sometimes checked as items in bags for re-application)
    "Sophic Devotion", "Celestial Guidance", "Wafting Devotion", "Authority of Radiant Power"
}

-- BUFF SLOT RESTRICTIONS (NIL = ANY SLOT)
local BUFF_RESTRICTIONS = {
    ["Algari Mana Oil"] = 16,    -- Main Hand Only (Per Request)
    ["Windfury Weapon"] = 16,    -- Main Hand Only (Shaman)
    ["Sunfury Whetstone"] = 16,  -- Main Hand Only (Midnight Lore)
}

-- FACTION STANDING COLORS (Native WoW Palette)
local FACTION_BAR_COLORS = {
    [1] = {r = 0.8, g = 0.3, b = 0.22}, -- Hated (Red)
    [2] = {r = 0.8, g = 0.3, b = 0.22}, -- Hostile
    [3] = {r = 0.75, g = 0.27, b = 0},  -- Unfriendly (Orange)
    [4] = {r = 0.9, g = 0.7, b = 0},    -- Neutral (Yellow)
    [5] = {r = 0, g = 0.6, b = 0.1},    -- Friendly (Green)
    [6] = {r = 0, g = 0.6, b = 0.1},    -- Honored
    [7] = {r = 0, g = 0.6, b = 0.1},    -- Revered
    [8] = {r = 0, g = 1, b = 1},        -- Exalted (Cyan)
}

-- GEM LOOKUP TABLE
local GEM_STATS_DB = {
    ["Culminating Blasphemite"] = "+181 Primary Stat + 1% Critical Effect",
    ["Elusive Blasphemite"]     = "+181 Primary Stat + 2% Movement Speed",
    ["Insightful Blasphemite"]  = "+181 Primary Stat + 1% Max Mana",
    ["Cubic Blasphemia"]        = "+181 Primary Stat + 20% Fame/Fortune",
    ["Cognitive Bloodstone"]    = "+181 Primary Stat + Precognition",
    ["Enduring Bloodstone"]     = "+181 Primary Stat + 15% Dmg Reduction (CC)",
    ["Determined Bloodstone"]   = "+181 Primary Stat + Snare Dmg Boost",
    ["Quick Emerald"]           = "+317 Haste",
    ["Deadly Emerald"]          = "+190 Haste / +127 Critical Strike",
    ["Masterful Emerald"]       = "+190 Haste / +127 Mastery",
    ["Versatile Emerald"]       = "+190 Haste / +127 Versatility",
    ["Deadly Ruby"]             = "+317 Critical Strike",
    ["Quick Ruby"]              = "+190 Critical Strike / +127 Haste",
    ["Masterful Ruby"]          = "+190 Critical Strike / +127 Mastery",
    ["Versatile Ruby"]          = "+190 Critical Strike / +127 Versatility",
    ["Masterful Onyx"]          = "+317 Mastery",
    ["Quick Onyx"]              = "+190 Mastery / +127 Haste",
    ["Deadly Onyx"]             = "+190 Mastery / +127 Critical Strike",
    ["Versatile Onyx"]          = "+190 Mastery / +127 Versatility",
    ["Versatile Sapphire"]      = "+317 Versatility",
    ["Quick Sapphire"]          = "+190 Versatility / +127 Haste",
    ["Deadly Sapphire"]         = "+190 Versatility / +127 Critical Strike",
    ["Masterful Sapphire"]      = "+190 Versatility / +127 Mastery",
    ["Solid Amber"]             = "+317 Stamina",
    ["Quick Amber"]             = "+190 Stamina / +127 Haste",
    ["Deadly Amber"]            = "+190 Stamina / +127 Critical Strike",
    ["Masterful Amber"]         = "+190 Stamina / +127 Mastery",
    ["Versatile Amber"]         = "+190 Stamina / +127 Versatility"
}

-- ENHANCEMENT DESCRIPTIONS DATABASE
local ENHANCEMENT_DESCRIPTIONS = {
    [1] = "Critical Strike increases your chance to deal additional damage or healing.",
    [2] = "Haste increases attack speed, reduces cast times, and lowers cooldowns.",
    [3] = "Mastery enhances your specialization's unique abilities.",
    [4] = "Versatility increases damage/healing dealt and reduces damage taken.",
    [5] = "Leech heals you for a percentage of damage/healing done.",
    [6] = "Avoidance reduces AoE damage taken.",
    [7] = "Speed increases your movement speed."
}

-- =========================================================================
-- 1. HELPERS & RAIDER.IO ENGINE
-- =========================================================================

local function GetRegionName()
    local regionID = GetCurrentRegion()
    if regionID == 1 then return "us"
    elseif regionID == 2 then return "kr"
    elseif regionID == 3 then return "eu"
    elseif regionID == 4 then return "tw"
    elseif regionID == 5 then return "cn"
    else return "us" end
end

local function GetFactionID()
    local factionGroup = UnitFactionGroup("player")
    if factionGroup == "Alliance" then return 1 else return 2 end
end

local function GetRioColor(s)
    if not s or s == 0 then return "|cffffffff" end
    if s >= 3000 then return "|cffff8000" 
    elseif s >= 2500 then return "|cffa335ee" 
    elseif s >= 2000 then return "|cff0070dd" 
    elseif s >= 1000 then return "|cff1eff00" 
    else return "|cffffffff" end
end

local function GetProgColor(str)
    if not str or str == "-" then return "|cff888888" end -- GREY
    
    local kills = tonumber(string.match(str, "^(%d+)")) or 0
    
    if kills == 8 then return "|cffff8000" -- ORANGE (Legendary)
    elseif kills >= 5 then return "|cffa335ee" -- PURPLE (Epic) (5, 6, 7)
    elseif kills > 0 then return "|cff00ff00" -- GREEN (1, 2, 3, 4)
    else return "|cff888888" -- GREY (0)
    end
end

-- DYNAMIC VERSION CONTROL (11.x vs 12.x)
local function GetIlvlColor(ilvl)
    local val = tonumber(ilvl) or 0
    local _, _, _, toc = GetBuildInfo()
    
    if toc >= 120000 then 
        -- MIDNIGHT (12.x)
        if val > 160 then return "|cffff8000" -- Orange
        elseif val >= 145 then return "|cffa335ee" -- Purple
        else return "|cff00ff00" -- Green/Blue (Low)
        end
    else 
        -- CURRENT (11.x)
        if val > 727 then return "|cffff8000" -- Orange (Legendary)
        elseif val >= 715 then return "|cffa335ee" -- Purple
        else return "|cff00ff00" -- Green
        end
    end
end

-- HELPER: WARBAND TRANSFER OPENER (Revised Logic)
local function OpenWarbandTransfer(currencyID)
    -- 1. Ensure Blizz TokenUI is loaded
    if not C_AddOns.IsAddOnLoaded("Blizzard_TokenUI") then
        C_AddOns.LoadAddOn("Blizzard_TokenUI")
    end
    
    -- 2. Request Data immediately
    C_CurrencyInfo.RequestCurrencyDataForAccountCharacters()

    -- 3. Target the Frame
    local frame = _G.CurrencyTransferMenu
    
    if frame then
        -- 4. HARD FIX: UN-ANCHOR AND RE-PARENT
        -- AXIOM sterilizes TokenFrame (hides it and moves it to dummy dump).
        -- If CurrencyTransferMenu is parented to TokenFrame, it becomes invisible or 0x0.
        frame:SetParent(UIParent)
        
        -- FORCE break previous anchors to avoid snapping to hidden frames
        frame:ClearAllPoints()
        frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
        
        -- 5. Force Strata ABOVE AXIOM (AXIOM is HIGH/900)
        frame:SetFrameStrata("FULLSCREEN_DIALOG")
        
        -- 6. Execute Open Method
        if frame.OpenFrame then
            frame:OpenFrame(currencyID)
            frame:Show() -- Redundant safety show
        else
            if frame.SetCurrency then frame:SetCurrency(currencyID) end
            frame:Show()
        end
    else
        print(COLOR_RED.."AXIOM CRITICAL ERROR: CurrencyTransferMenu not found. Blizzard_TokenUI failed to initialize.|r")
    end
end

local function FetchRaiderIOData()
    local results = {
        score = 0,
        raidN = "-",
        raidH = "-",
        raidM = "-",
        dungeons = {}
    }

    if not _G.RaiderIO or not _G.RaiderIO.GetProfile then return results end

    local name = UnitName("player")
    local _, realm = UnitFullName("player")
    local region = GetRegionName()
    local factionID = GetFactionID()

    local p = _G.RaiderIO.GetProfile(name, realm, factionID)
    if not p then
        local otherFaction = (factionID == 1) and 2 or 1
        p = _G.RaiderIO.GetProfile(name, realm, otherFaction)
    end
    if not p then p = _G.RaiderIO.GetProfile(name, realm, region) end

    if p then
        if p.mythicKeystoneProfile then
            results.score = p.mythicKeystoneProfile.currentScore or 0
        end

        if p.raidProfile and p.raidProfile.progress then
            local currentTierPriority = 0
            for _, prog in ipairs(p.raidProfile.progress) do
                local rName = string.lower(prog.raid and prog.raid.name or "")
                local tier = 0
                if string.find(rName, "manaforge") or string.find(rName, "omega") then tier = 3
                elseif string.find(rName, "liberation") or string.find(rName, "undermine") then tier = 2
                elseif string.find(rName, "nerub") or string.find(rName, "palace") then tier = 1 end

                if tier > 0 and tier >= currentTierPriority then
                    if tier > currentTierPriority then
                        results.raidN, results.raidH, results.raidM = "-", "-", "-"
                        currentTierPriority = tier
                    end
                    local kills = prog.progressCount or 0
                    local total = prog.raid and prog.raid.bossCount or 8
                    local str = kills .. "/" .. total
                    if prog.difficulty == 1 then results.raidN = str
                    elseif prog.difficulty == 2 then results.raidH = str
                    elseif prog.difficulty == 3 then results.raidM = str end
                end
            end
        end

        if p.mythicKeystoneProfile and p.mythicKeystoneProfile.sortedDungeons then
            for _, run in ipairs(p.mythicKeystoneProfile.sortedDungeons) do
                if run.dungeon and run.dungeon.shortName then
                    results.dungeons[run.dungeon.shortName] = run.level
                end
            end
        end
    end
    return results
end

local function GetSpecColor(specID, classFile)
    if SPEC_COLORS[specID] then
        return "|c" .. SPEC_COLORS[specID]
    else
        local c = C_ClassColor.GetClassColor(classFile or "PRIEST")
        return c and c:GenerateHexColorMarkup() or "|cffffffff"
    end
end

-- =========================================================================
-- 2. RESKIN CORE & STERILIZATION ENGINE
-- =========================================================================

local AXIOM_Armory = CreateFrame("Frame", "AXIOM_Armory_Frame_Reboot", CharacterFrame, "BackdropTemplate")
AXIOM_Armory.ViewingUnit = "player" 
AXIOM_Armory.ShowExtras = false 

local AXIOM_HiddenDump = CreateFrame("Frame", "AXIOM_HiddenDump", UIParent)
AXIOM_HiddenDump:SetSize(1,1)
AXIOM_HiddenDump:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -2000, -2000)
AXIOM_HiddenDump:Hide()

local function SterilizeNativeUI()
    if InCombatLockdown() then return end
    if not AXIOM_System_Enabled then return end -- Flag Check

    local framesToNuke = {
        CharacterFrameInset,
        CharacterFrameInsetRight,
        CharacterFrameBg,           
        CharacterFramePortrait,
        CharacterFramePortraitFrame,
        CharacterFrameTitleBg,
        CharacterFrameCloseButton,
        CharacterStatsPane,
        PaperDollFrame,             
        TokenFrame,
        ReputationFrame,
        CurrencyFrame,
        CharacterModelScene,        
        CharacterModelFrame,        
        PaperDollSidebarTabs,       
        CharacterFrameTab1,
        CharacterFrameTab2,
        CharacterFrameTab3,
        CharacterFrameTab4,
        -- Inspect frames handled elsewhere
    }

    for _, f in pairs(framesToNuke) do
        if f and f:GetParent() ~= AXIOM_HiddenDump then
            -- Store for restoration
            if not RESTORE_QUEUE[f] then
                RESTORE_QUEUE[f] = f:GetParent()
            end
            
            f:Hide()
            f:EnableMouse(false)
            f:SetParent(AXIOM_HiddenDump) 
        end
    end

    local regions = {CharacterFrame:GetRegions()}
    for _, region in ipairs(regions) do
        if region:IsObjectType("Texture") then
            -- MODIFICATION: Just hide, do not destroy texture to allow toggle restoration
            region:Hide()
        end
    end

    local kids = {CharacterFrame:GetChildren()}
    for _, child in ipairs(kids) do
        if child ~= AXIOM_Armory and child:GetParent() ~= AXIOM_HiddenDump then
            if not RESTORE_QUEUE[child] then
                RESTORE_QUEUE[child] = child:GetParent()
            end
            child:Hide()
            child:SetParent(AXIOM_HiddenDump)
        end
    end
end

local function RestoreNativeUI()
    if InCombatLockdown() then return end
    
    -- Restore Parentage
    for frame, originalParent in pairs(RESTORE_QUEUE) do
        if frame then
            frame:SetParent(originalParent or CharacterFrame)
            frame:EnableMouse(true) -- Re-enable interaction
            
            -- CRITICAL FIX: Force Show if the parent (CharacterFrame) is visible
            -- This ensures headers/portraits/borders reappear immediately on toggle
            if CharacterFrame:IsShown() then
                frame:Show()
            end
        end
    end
    RESTORE_QUEUE = {} -- Clear Queue

    -- Restore Regions
    local regions = {CharacterFrame:GetRegions()}
    for _, region in ipairs(regions) do
        if region:IsObjectType("Texture") then
            region:Show() -- Unhide
        end
    end
    
    -- Handle Sub-Frames that should be visible on default char sheet
    if CharacterFrame:IsShown() then
        if CharacterFrameInset then CharacterFrameInset:Show() end
        if CharacterFrameInsetRight then CharacterFrameInsetRight:Show() end
        if PaperDollFrame then PaperDollFrame:Show() end
        if PaperDollSidebarTabs then PaperDollSidebarTabs:Show() end
        if CharacterModelScene then CharacterModelScene:Show() end
        
        -- Explicit Integrity Check for Structural Elements
        if CharacterFramePortrait then CharacterFramePortrait:Show() end
        if CharacterFramePortraitFrame then CharacterFramePortraitFrame:Show() end
        if CharacterFrameTitleBg then CharacterFrameTitleBg:Show() end
        if CharacterFrameCloseButton then CharacterFrameCloseButton:Show() end
        if CharacterFrameBg then CharacterFrameBg:Show() end
    end
end

-- PUBLIC API for Settings.lua
function AXIOM_Armory:ToggleSystem(enabled)
    AXIOM_System_Enabled = enabled
    
    if enabled then
        -- Enable: Check if we are currently looking at CharacterFrame. If so, hijack immediately.
        if CharacterFrame:IsShown() then
            AXIOM_Armory:SetUnit("player")
            AXIOM_Armory:Show()
            SterilizeNativeUI()
        end
    else
        -- Disable: Restore native, hide custom
        AXIOM_Armory:Hide()
        RestoreNativeUI()
    end
end

local function BuildReskin()
    if not CharacterFrame then return end 
    
    AXIOM_Armory:SetSize(FRAME_WIDTH, FRAME_HEIGHT)
    AXIOM_Armory:SetPoint("CENTER", CharacterFrame, "CENTER", 0, 0)
    AXIOM_Armory:SetMovable(true) 
    
    -- [[ STRATA ELEVATION PROTOCOL ]]
    AXIOM_Armory:SetFrameStrata("FULLSCREEN") 
    AXIOM_Armory:SetFrameLevel(900)     
    AXIOM_Armory:SetAlpha(1)
    
    local bg = AXIOM_Armory:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints(AXIOM_Armory)
    bg:SetColorTexture(0.05, 0.05, 0.05, 0.98)

    local border = CreateFrame("Frame", nil, AXIOM_Armory, "BackdropTemplate")
    border:SetAllPoints()
    border:SetBackdrop({
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 16,
    })
    border:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)

    local header = CreateFrame("Frame", nil, AXIOM_Armory)
    header:SetSize(FRAME_WIDTH, HEADER_HEIGHT)
    header:SetPoint("TOP", AXIOM_Armory, "TOP", 0, 0)
    
    header:EnableMouse(true)
    header:RegisterForDrag("LeftButton")
    header:SetScript("OnDragStart", function() AXIOM_Armory:StartMoving() end)
    header:SetScript("OnDragStop", function() AXIOM_Armory:StopMovingOrSizing() end)
    
    local hbg = header:CreateTexture(nil, "BACKGROUND")
    hbg:SetAllPoints()
    hbg:SetColorTexture(0, 0, 0, 1)

    -- CRITICAL FIX: Store Title as Property, avoid global name
    AXIOM_Armory.Title = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    AXIOM_Armory.Title:SetPoint("LEFT", 10, 0)
    AXIOM_Armory.Title:SetText(COLOR_BLUE .. "A.X.I.O.M.|r | ARMORY")

    local close = CreateFrame("Button", nil, header, "BackdropTemplate")
    close:SetSize(20, 20)
    close:SetPoint("TOPRIGHT", -5, -5)
    close:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground" })
    close:SetBackdropColor(0.2, 0.1, 0.1, 1)
    
    local closeTxt = close:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    closeTxt:SetPoint("CENTER", 0, 0); closeTxt:SetText("X"); closeTxt:SetTextColor(1, 1, 1)
    close:SetScript("OnClick", function() 
        AXIOM_Armory:Hide()
        HideUIPanel(CharacterFrame) 
    end)
end

-- =========================================================================
-- 3. ARMORY TABS & LEFT PANE CONTAINER
-- =========================================================================

local ScannerTooltip = CreateFrame("GameTooltip", "AXIOM_ScannerTooltip", nil, "GameTooltipTemplate")
ScannerTooltip:SetOwner(UIParent, "ANCHOR_NONE")

-- HELPER: GEM STATS LOOKUP
local function AXIOM_GetGemStats(gemID)
    if not gemID then return nil end
    
    local name = GetItemInfo(gemID)
    if not name then return "Loading..." end 
    
    if GEM_STATS_DB[name] then
        return GEM_STATS_DB[name]
    end
    
    return name
end

local function GetItemExtras(unit, slotID)
    local link = GetInventoryItemLink(unit, slotID)
    if not link then return nil end
    
    local info = { enchant = nil, gems = {}, embellish = nil }
    
    -- 1. Scan Tooltip for "Enchanted: ..." & Embellishment
    ScannerTooltip:ClearLines()
    ScannerTooltip:SetHyperlink(link)
    local lines = ScannerTooltip:NumLines()
    
    for i = 2, lines do
        local line = _G["AXIOM_ScannerTooltipTextLeft"..i]
        if line then
            local text = line:GetText() or ""
            
            if string.find(text, "^Enchanted: ") then
                info.enchant = string.gsub(text, "^Enchanted: ", "")
            end
            
            if string.find(text, "Embellished") then
                info.embellish = "Embellished"
            elseif string.find(text, "Unique%-Equipped: .* %(%d%)") then
                info.embellish = "Crafted"
            end
        end
    end

    -- 2. Parse Link for Gems
    local itemString = string.match(link, "item[%-?%d:]+") or ""
    local parts = { strsplit(":", itemString) }
    
    for i = 4, 7 do
        if parts[i] and parts[i] ~= "" and parts[i] ~= "0" then
            local gemID = tonumber(parts[i])
            if gemID then
                local statStr = AXIOM_GetGemStats(gemID)
                table.insert(info.gems, statStr)
            end
        end
    end
    
    return info
end

-- =========================================================================
-- WEAPON ENHANCEMENT LOGIC (MACRO ENGINE)
-- =========================================================================

local securePool = {}
local function GetSecureButton(parent, index)
    if not securePool[index] then
        -- Secure Button Construction
        local btn = CreateFrame("Button", "AXIOM_SecureBtn_"..index, parent, "SecureActionButtonTemplate, BackdropTemplate")
        btn:SetSize(30, 30)
        btn:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 1 })
        btn:SetBackdropColor(0.2, 0.2, 0.2, 1) -- Button visual background
        
        -- CRITICAL: Register Clicks explicitly for Secure Templates
        btn:RegisterForClicks("AnyUp", "AnyDown")
        btn:EnableMouse(true)
        
        btn.icon = btn:CreateTexture(nil, "ARTWORK")
        btn.icon:SetAllPoints()
        btn.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        btn:SetScript("OnEnter", function(self)
            if self.buffName then
                GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                GameTooltip:SetText(self.buffName)
                GameTooltip:Show()
            end
        end)
        btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        securePool[index] = btn
    end
    return securePool[index]
end

local function PopulateFlyout(flyout, slotID)
    if InCombatLockdown() then return end
    
    -- Hide all existing
    for _, btn in pairs(securePool) do btn:Hide(); btn:SetParent(AXIOM_HiddenDump) end
    
    local found = {}
    
    -- Scan for items/spells in the Precise List
    for _, buffName in ipairs(WEAPON_ENHANCEMENTS) do
        -- 1. CHECK RESTRICTIONS
        local allowedSlot = BUFF_RESTRICTIONS[buffName]
        if not allowedSlot or allowedSlot == slotID then
            local isItem = false
            local isSpell = false
            local icon = nil
            
            -- Check Bag (Item)
            if GetItemCount(buffName) > 0 then
                isItem = true
                icon = GetItemIcon(buffName)
            
            -- Check Spellbook (Spell) via modern C_Spell API
            else
                local spellInfo = C_Spell.GetSpellInfo(buffName)
                if spellInfo then
                    if IsSpellKnown(spellInfo.spellID) then
                        isSpell = true
                        icon = spellInfo.iconID
                    end
                end
            end
            
            if (isItem or isSpell) and icon then
                table.insert(found, { name = buffName, isItem = isItem, icon = icon })
            end
        end
    end

    local row, col = 0, 0
    for i, data in ipairs(found) do
        local btn = GetSecureButton(flyout, i)
        btn:SetParent(flyout)
        -- CRITICAL: Ensure Button Level is HIGHER than Flyout (FrameLevel) to receive clicks
        btn:SetFrameLevel(flyout:GetFrameLevel() + 10)
        btn:SetPoint("TOPLEFT", 5 + (col*35), -5 - (row*35))
        btn:Show()
        btn.icon:SetTexture(data.icon)
        btn.buffName = data.name
        
        -- SECURE MACRO ATTRIBUTES (Left Click Specific)
        btn:SetAttribute("type1", "macro") -- Left Click
        
        if data.isItem then
            -- Item Macro: Use Item, then Target Slot
            local macroText = "/stopmacro [combat]\n/use " .. data.name .. "\n/use " .. slotID
            btn:SetAttribute("macrotext", macroText)
        else
            -- Spell Macro: Cast Spell
            local macroText = "/stopmacro [combat]\n/cast " .. data.name
            btn:SetAttribute("macrotext", macroText)
        end
        
        col = col + 1
        if col > 3 then col = 0; row = row + 1 end
    end
    
    local totalRows = row + 1
    if col == 0 and row > 0 then totalRows = row end
    flyout:SetHeight((totalRows * 35) + 10)
end

local function CreateWeaponExpandButton(parent, slotID, anchorSlot)
    local expandBtn = CreateFrame("Button", nil, parent)
    expandBtn:SetSize(15, 34)
    expandBtn:SetPoint("LEFT", anchorSlot, "RIGHT", 2, 0)
    
    expandBtn.text = expandBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    expandBtn.text:SetPoint("CENTER", 0, 0)
    expandBtn.text:SetText(COLOR_GOLD .. "|>|r")
    
    -- Flyout Container
    local flyout = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    flyout:SetWidth(150)
    flyout:SetPoint("TOPLEFT", expandBtn, "TOPRIGHT", 5, 0)
    
    -- [[ STRATA ELEVATION: POPUP ]]
    flyout:SetFrameStrata("FULLSCREEN_DIALOG")
    flyout:SetFrameLevel(950)
    
    -- BACKGROUND: SOLID BLACK LAYER (Manual Texture)
    local bg = flyout:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0, 0, 0, 1) -- PURE SOLID BLACK
    
    -- BORDER: VIA BACKDROP
    flyout:SetBackdrop({ 
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 
        edgeSize = 16, 
        insets = {left=4, right=4, top=4, bottom=4} 
    })
    flyout:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) 
    
    flyout:Hide()
    
    expandBtn:SetScript("OnClick", function()
        if flyout:IsShown() then
            flyout:Hide()
            expandBtn.text:SetText(COLOR_GOLD .. "|>|r")
        else
            if InCombatLockdown() then 
                print("|cffff0000AXIOM: Cannot change equipment/buffs in combat.|r") 
                return 
            end
            flyout:Show()
            expandBtn.text:SetText(COLOR_GOLD .. "<| |r")
            PopulateFlyout(flyout, slotID)
        end
    end)
    
    return expandBtn
end

local function BuildArmoryLeft()
    local leftMain = CreateFrame("Frame", "AXIOM_Armory_Left", AXIOM_Armory)
    leftMain:SetSize(400, FRAME_HEIGHT - HEADER_HEIGHT) 
    leftMain:SetPoint("TOPLEFT", AXIOM_Armory, "TOPLEFT", 10, -HEADER_HEIGHT - 10)
    AXIOM_Armory.LeftMain = leftMain

    -- ===========================
    -- SUB-PANE 1: CHARACTER (GEAR)
    -- ===========================
    local charPane = CreateFrame("Frame", nil, leftMain)
    charPane:SetAllPoints()
    AXIOM_Armory.CharPane = charPane

    -- CRITICAL FIX: Store FontStrings as properties
    AXIOM_Armory.NameStr = charPane:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    AXIOM_Armory.NameStr:SetPoint("TOP", 0, -10); AXIOM_Armory.NameStr:SetText(UnitName("player"))
    
    AXIOM_Armory.GuildStr = charPane:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    AXIOM_Armory.GuildStr:SetPoint("TOP", AXIOM_Armory.NameStr, "BOTTOM", 0, -5); AXIOM_Armory.GuildStr:SetText("")

    AXIOM_Armory.DetailStr = charPane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    AXIOM_Armory.DetailStr:SetPoint("TOP", AXIOM_Armory.GuildStr, "BOTTOM", 0, -5)
    AXIOM_Armory.DetailStr:SetText("Loading...")

    -- Extra's Toggle
    local extraBtn = CreateFrame("Button", nil, charPane, "GameMenuButtonTemplate")
    extraBtn:SetSize(100, 20)
    extraBtn:SetPoint("TOP", AXIOM_Armory.DetailStr, "BOTTOM", 0, -5)
    extraBtn:SetText("Toggle Extra's")
    extraBtn:SetScript("OnClick", function()
        AXIOM_Armory.ShowExtras = not AXIOM_Armory.ShowExtras
        AXIOM_Armory:UpdateItems() 
    end)

    local model = CreateFrame("PlayerModel", "AXIOM_PlayerModel", charPane)
    model:SetSize(250, 280); model:SetPoint("CENTER", 0, -30); model:SetUnit("player")

    AXIOM_Armory.Slots = {}
    local startY = -70
    local slotSize = 40 -- RESIZED to 40x40
    
    for i, slotData in ipairs(INV_SLOTS) do
        local slot = CreateFrame("Button", nil, charPane, "BackdropTemplate")
        slot:SetSize(slotSize, slotSize)
        slot:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 1 })
        slot:SetBackdropColor(0, 0, 0, 0.5)
        
        local isLeft = (i <= 8)
        if isLeft then 
            slot:SetPoint("TOPLEFT", 0, startY - ((i-1)*(slotSize + 5)))
        else 
            slot:SetPoint("TOPRIGHT", 0, startY - ((i-9)*(slotSize + 5))) 
        end
        
        slot.icon = slot:CreateTexture(nil, "ARTWORK"); slot.icon:SetAllPoints(); slot.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        -- LAYER: DIMMER (Black 25% Opacity)
        local dimmer = slot:CreateTexture(nil, "OVERLAY")
        dimmer:SetAllPoints()
        dimmer:SetColorTexture(0, 0, 0, 0.25)
        slot.Dimmer = dimmer

        -- OVERLAY: Item Level Text (BOTTOM CENTER)
        local ilvlTxt = slot:CreateFontString(nil, "OVERLAY")
        ilvlTxt:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE") -- CHANGED: Increased Size (Was ~13 via Template)
        ilvlTxt:SetPoint("BOTTOM", slot, "BOTTOM", 0, 2)
        ilvlTxt:SetJustifyH("CENTER")
        slot.IlvlText = ilvlTxt
        
        -- Extras Text
        local extraTxt = slot:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        if isLeft then
            extraTxt:SetPoint("LEFT", slot, "RIGHT", 5, 0)
            extraTxt:SetJustifyH("LEFT")
        else
            extraTxt:SetPoint("RIGHT", slot, "LEFT", -5, 0)
            extraTxt:SetJustifyH("RIGHT")
        end
        slot.ExtraText = extraTxt

        slot:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            local link = GetInventoryItemLink("player", slotData.id)
            if link then GameTooltip:SetHyperlink(link) else GameTooltip:SetText(slotData.name) end
            GameTooltip:Show()
        end)
        slot:SetScript("OnLeave", function() GameTooltip:Hide() end)

        slot:RegisterForClicks("LeftButtonUp", "RightButtonUp")
        slot:SetScript("OnClick", function(self, button)
            if button == "LeftButton" then PickupInventoryItem(slotData.id)
            elseif button == "RightButton" then UseInventoryItem(slotData.id) end
        end)
        
        -- EXPAND BUTTONS FOR WEAPONS (SLOT 16/17)
        if slotData.id == 16 or slotData.id == 17 then
            local expand = CreateWeaponExpandButton(charPane, slotData.id, slot)
            -- STORE BUTTON FOR VISIBILITY LOGIC
            slot.ExpandBtn = expand 
        end

        AXIOM_Armory.Slots[slotData.id] = slot
    end

    -- ===========================
    -- SUB-PANE 2: REPUTATION
    -- ===========================
    local repPane = CreateFrame("ScrollFrame", "AXIOM_RepScroll", leftMain, "UIPanelScrollFrameTemplate")
    repPane:SetPoint("TOPLEFT", 0, -10)
    repPane:SetPoint("BOTTOMRIGHT", -25, 40)
    repPane:Hide()
    if NS.StyleScrollBar then NS.StyleScrollBar(repPane) end
    AXIOM_Armory.RepPane = repPane

    local repContent = CreateFrame("Frame", nil, repPane)
    repContent:SetSize(375, 500) 
    repPane:SetScrollChild(repContent)
    AXIOM_Armory.RepContent = repContent
    
    -- INIT DETAIL FRAME (Popup)
    local detail = CreateFrame("Frame", "AXIOM_RepDetailFrame", leftMain, "BackdropTemplate")
    detail:SetSize(250, 180) 
    detail:SetPoint("CENTER", 0, 0)
    detail:SetBackdrop({ bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 16, insets = {left=4, right=4, top=4, bottom=4} })
    detail:SetBackdropColor(0,0,0,0.95)
    detail:Hide()
    
    -- [[ STRATA ELEVATION: POPUP ]]
    detail:SetFrameStrata("FULLSCREEN_DIALOG")
    
    detail.Name = detail:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    detail.Name:SetPoint("TOP", 0, -10)
    
    detail.Desc = detail:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    detail.Desc:SetPoint("TOP", detail.Name, "BOTTOM", 0, -5)
    detail.Desc:SetWidth(230)
    detail.Desc:SetWordWrap(true)
    
    detail.WatchCheck = CreateFrame("CheckButton", nil, detail, "UICheckButtonTemplate")
    detail.WatchCheck:SetSize(26, 26) -- Fixed Size
    detail.WatchCheck.text = detail.WatchCheck:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    detail.WatchCheck.text:SetPoint("LEFT", detail.WatchCheck, "RIGHT", 5, 0)
    detail.WatchCheck.text:SetText("Show as Experience Bar")
    
    detail.WarCheck = CreateFrame("CheckButton", nil, detail, "UICheckButtonTemplate")
    detail.WarCheck:SetSize(26, 26) -- Fixed Size
    detail.WarCheck.text = detail.WarCheck:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    detail.WarCheck.text:SetPoint("LEFT", detail.WarCheck, "RIGHT", 5, 0)
    detail.WarCheck.text:SetText("At War")
    
    detail.InactiveCheck = CreateFrame("CheckButton", nil, detail, "UICheckButtonTemplate")
    detail.InactiveCheck:SetSize(26, 26) -- Fixed Size
    detail.InactiveCheck.text = detail.InactiveCheck:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    detail.InactiveCheck.text:SetPoint("LEFT", detail.InactiveCheck, "RIGHT", 5, 0)
    detail.InactiveCheck.text:SetText("Inactive")
    
    detail.RenownBtn = CreateFrame("Button", nil, detail, "GameMenuButtonTemplate")
    detail.RenownBtn:SetSize(140, 20)
    detail.RenownBtn:SetText("View Renown")
    
    detail.Close = CreateFrame("Button", nil, detail, "UIPanelCloseButton")
    detail.Close:SetPoint("TOPRIGHT", -2, -2)
    detail.Close:SetScript("OnClick", function() detail:Hide() end)
    
    AXIOM_Armory.RepDetail = detail

    -- ===========================
    -- SUB-PANE 3: CURRENCY
    -- ===========================
    local currPane = CreateFrame("ScrollFrame", "AXIOM_CurrScroll", leftMain, "UIPanelScrollFrameTemplate")
    currPane:SetPoint("TOPLEFT", 0, -10)
    currPane:SetPoint("BOTTOMRIGHT", -25, 40)
    currPane:Hide()
    if NS.StyleScrollBar then NS.StyleScrollBar(currPane) end
    AXIOM_Armory.CurrPane = currPane

    local currContent = CreateFrame("Frame", nil, currPane)
    currContent:SetSize(375, 500) 
    currPane:SetScrollChild(currContent)
    AXIOM_Armory.CurrContent = currContent

    -- Currency Detail Frame (Popup)
    local cDetail = CreateFrame("Frame", "AXIOM_CurrencyDetailFrame", leftMain, "BackdropTemplate")
    cDetail:SetSize(250, 180) 
    cDetail:SetPoint("CENTER", 0, 0)
    cDetail:SetBackdrop({
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 16,
        insets = {left=4, right=4, top=4, bottom=4}
    })
    cDetail:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)
    local cDetailBg = cDetail:CreateTexture(nil, "BACKGROUND")
    cDetailBg:SetAllPoints()
    cDetailBg:SetColorTexture(0.02, 0.02, 0.02, 0.98) -- Darker background
    cDetail:Hide()
    
    -- [[ STRATA ELEVATION: POPUP ]]
    cDetail:SetFrameStrata("FULLSCREEN_DIALOG")

    cDetail.Icon = cDetail:CreateTexture(nil, "ARTWORK")
    cDetail.Icon:SetSize(32, 32)
    cDetail.Icon:SetPoint("TOPLEFT", 10, -10)

    cDetail.Name = cDetail:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    cDetail.Name:SetPoint("TOPLEFT", cDetail.Icon, "TOPRIGHT", 10, 0)

    cDetail.Count = cDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    cDetail.Count:SetPoint("TOPLEFT", cDetail.Name, "BOTTOMLEFT", 0, -5)

    cDetail.Desc = cDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    cDetail.Desc:SetPoint("TOPLEFT", cDetail.Count, "BOTTOMLEFT", 0, -10)
    cDetail.Desc:SetWidth(230)
    cDetail.Desc:SetWordWrap(true)

    cDetail.TransferBtn = CreateFrame("Button", nil, cDetail, "GameMenuButtonTemplate")
    cDetail.TransferBtn:SetSize(140, 22)
    cDetail.TransferBtn:SetText("Transfer to Warband")
    cDetail.TransferBtn:Hide()

    cDetail.BackpackCheck = CreateFrame("CheckButton", nil, cDetail, "UICheckButtonTemplate")
    cDetail.BackpackCheck:SetSize(26, 26)
    cDetail.BackpackCheck.text = cDetail.BackpackCheck:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    cDetail.BackpackCheck.text:SetPoint("LEFT", cDetail.BackpackCheck, "RIGHT", 5, 0)
    cDetail.BackpackCheck.text:SetText("Show on Backpack Bar")

    local closeBtn = CreateFrame("Button", nil, cDetail, "UIPanelCloseButton")
    closeBtn:SetPoint("TOPRIGHT", -2, -2)
    closeBtn:SetScript("OnClick", function() cDetail:Hide() end)

    AXIOM_Armory.CurrencyDetail = cDetail

    -- ===========================
    -- TABS (BOTTOM OF LEFT PANE)
    -- ===========================
    local tabW, tabH = 130, 25 
    local tabs = {"Character", "Reputation", "Currency"}
    AXIOM_Armory.Tabs = {}

    local function SetTab(id)
        AXIOM_Armory.CharPane:Hide()
        AXIOM_Armory.RepPane:Hide()
        AXIOM_Armory.CurrPane:Hide()
        
        for k, t in pairs(AXIOM_Armory.Tabs) do
            t.bg:SetColorTexture(0.1, 0.1, 0.1, 1)
            t.text:SetTextColor(0.5, 0.41, 0)
        end
        AXIOM_Armory.Tabs[id].bg:SetColorTexture(0.5, 0.5, 0.5, 1)
        AXIOM_Armory.Tabs[id].text:SetTextColor(1, 0.82, 0)

        if id == 1 then AXIOM_Armory.CharPane:Show()
        elseif id == 2 then 
            AXIOM_Armory.RepPane:Show()
            AXIOM_Armory:UpdateReputation()
        elseif id == 3 then 
            AXIOM_Armory.CurrPane:Show()
            
            -- PRIMING: Ensure Currency Data is ready when tab opens
            -- This prevents empty transfer windows
            if not C_AddOns.IsAddOnLoaded("Blizzard_TokenUI") then
                C_AddOns.LoadAddOn("Blizzard_TokenUI")
            end
            C_CurrencyInfo.RequestCurrencyDataForAccountCharacters()
            
            AXIOM_Armory:UpdateCurrency()
        end
    end

    for i, name in ipairs(tabs) do
        local btn = CreateFrame("Button", nil, leftMain)
        btn:SetFrameLevel(1)
        btn:SetSize(tabW, tabH)
        btn:SetPoint("BOTTOMLEFT", (i-1)*tabW + 5, -10)
        
        btn.bg = btn:CreateTexture(nil, "BACKGROUND")
        btn.bg:SetAllPoints()
        
        btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        btn.text:SetPoint("CENTER")
        btn.text:SetText(name)
        
        btn:SetScript("OnClick", function() SetTab(i) end)
        
        AXIOM_Armory.Tabs[i] = btn
    end
    
    SetTab(1) 
end

-- =========================================================================
-- REP & CURRENCY UPDATE LOGIC
-- =========================================================================

function AXIOM_Armory:UpdateReputation()
    local parent = self.RepContent
    if not parent.rows then parent.rows = {} end
    for _, r in pairs(parent.rows) do r:Hide() end
    
    -- HOOK: Refresh Detail Frame if open
    local dFrame = AXIOM_Armory.RepDetail
    local needsDetailRefresh = dFrame:IsShown() and dFrame.activeFactionID
    local foundActiveInUpdate = false

    local y = 0
    local count = 0
    local numFactions = C_Reputation.GetNumFactions()
    
    local currentHeader = ""
    for i = 1, numFactions do
        local data = C_Reputation.GetFactionDataByIndex(i)
        
        if data then
            count = count + 1
            local row = parent.rows[count]
            if not row then
                row = CreateFrame("Button", nil, parent)
                row:SetSize(360, 20)
                
                -- BG for Headers
                row.bg = row:CreateTexture(nil, "BACKGROUND")
                row.bg:SetAllPoints()
                row.bg:SetColorTexture(0.3, 0.3, 0.3, 0.5)
                row.bg:Hide()
                
                -- Arrow for Headers
                row.arrow = row:CreateTexture(nil, "OVERLAY")
                row.arrow:SetSize(16, 16)
                row.arrow:SetPoint("RIGHT", -10, 0)
                row.arrow:SetTexture("Interface\\Buttons\\UI-SortArrow")
                row.arrow:Hide()

                row.text = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                -- Point set dynamically below
                
                row.val = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                row.val:SetPoint("RIGHT", -30, 0) -- Adjusted to make room for arrow if needed
                
                row.bar = CreateFrame("StatusBar", nil, row)
                row.bar:SetAllPoints()
                row.bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
                row.bar:SetFrameLevel(row:GetFrameLevel() - 1)
                
                row.wbIcon = row:CreateTexture(nil, "OVERLAY")
                row.wbIcon:SetSize(16, 16)
                row.wbIcon:SetPoint("LEFT", row.text, "RIGHT", 5, 0)
                row.wbIcon:SetAtlas("account-wide-icon", true)
                row.wbIcon:Hide()
                
                parent.rows[count] = row
            end
            
            row:SetPoint("TOPLEFT", 0, -y)
            row.text:SetText(data.name)
            
            -- RESET VISUALS
            row.bar:SetStatusBarColor(0, 0.5, 0, 0.2)
            row.bar:SetMinMaxValues(0, 1)
            row.bar:SetValue(0)
            row.wbIcon:SetShown(data.isAccountWide)
            row.wbIcon:ClearAllPoints()
            
            -- COMMON CLICK HANDLER FUNCTION (To be called by row or refresh)
            local function OpenDetail()
                dFrame.activeFactionID = data.factionID -- Store for refresh
                dFrame:SetPoint("TOPRIGHT", row, "TOPLEFT", -5, 0)
                
                dFrame.Name:SetText(data.name)
                dFrame.Desc:SetText(data.description or "")
                
                local currentY = dFrame.Desc:GetStringHeight() + 40
                local isMajor = C_Reputation.IsMajorFaction(data.factionID)

                if isMajor then
                    -- RENOWN LAYOUT
                    dFrame.WarCheck:Hide()
                    dFrame.WatchCheck:Hide()
                    dFrame.InactiveCheck:Hide()
                    
                    dFrame.RenownBtn:Show()
                    dFrame.RenownBtn:SetPoint("TOP", dFrame.Desc, "BOTTOM", 0, -20)
                    dFrame.RenownBtn:SetScript("OnClick", function()
                        ToggleMajorFactionRenown(data.factionID)
                        dFrame:Hide()
                    end)
                    currentY = currentY + 30
                else
                    -- LEGACY LAYOUT
                    dFrame.RenownBtn:Hide()
                    
                    -- 1. WATCH (MODERN API)
                    dFrame.WatchCheck:Show()
                    dFrame.WatchCheck:SetPoint("TOPLEFT", dFrame.Desc, "BOTTOMLEFT", 0, -10)
                    dFrame.WatchCheck:SetChecked(data.isWatched)
                    dFrame.WatchCheck:SetScript("OnClick", function(self)
                        if self:GetChecked() then 
                            C_Reputation.SetWatchedFactionByID(data.factionID) 
                        else 
                            C_Reputation.SetWatchedFactionByID(0) -- CORRECT WAY TO CLEAR
                        end
                        -- NO IMMEDIATE UPDATE: Wait for UPDATE_FACTION event
                    end)
                    currentY = currentY + 30
                    
                    -- 2. AT WAR (Legacy uses Index)
                    dFrame.WarCheck:Show()
                    dFrame.WarCheck:SetPoint("TOPLEFT", dFrame.WatchCheck, "BOTTOMLEFT", 0, -5)
                    dFrame.WarCheck:SetChecked(data.atWarWith)
                    
                    if data.canToggleAtWar then
                        dFrame.WarCheck:Enable()
                        dFrame.WarCheck.text:SetTextColor(1, 1, 1)
                        dFrame.WarCheck:SetScript("OnClick", function(self)
                            FactionToggleAtWar(i) 
                            -- NO IMMEDIATE UPDATE: Wait for UPDATE_FACTION event
                        end)
                    else
                        dFrame.WarCheck:Disable()
                        dFrame.WarCheck.text:SetTextColor(0.5, 0.5, 0.5)
                        dFrame.WarCheck:SetScript("OnClick", nil)
                    end
                    currentY = currentY + 30
                    
                    -- 3. INACTIVE (Legacy uses Index)
                    dFrame.InactiveCheck:Show()
                    dFrame.InactiveCheck:SetPoint("TOPLEFT", dFrame.WarCheck, "BOTTOMLEFT", 0, -5)
                    dFrame.InactiveCheck:SetChecked(currentHeader == "Inactive") -- Default Visual Assumption
                    -- Logic: If checked, we want to SetInactive. If unchecked, SetActive.
                    dFrame.InactiveCheck:SetScript("OnClick", function(self)
                        if self:GetChecked() then
                            SetFactionInactive(i)
                        else
                            SetFactionActive(i)
                        end
                        -- NO IMMEDIATE UPDATE: Wait for UPDATE_FACTION event
                    end)
                    currentY = currentY + 30
                end
                
                dFrame:SetHeight(currentY + 20)
                dFrame:Show()
            end
            
            -- CHECK REFRESH
            if needsDetailRefresh and data.factionID == dFrame.activeFactionID then
                OpenDetail() -- Re-render open frame with new data
                foundActiveInUpdate = true
            end

            if data.isHeader then
                currentHeader = data.name
                -- HEADER STYLING
                row.text:SetPoint("LEFT", 5, 0) -- Level 0
                row.text:SetText(COLOR_GOLD .. data.name .. "|r")
                row.val:SetText("")
                row.bar:Hide()
                row.bg:Show()
                row.arrow:Show()
                
                if data.isCollapsed then
                    -- UP (Collapsed) -> Flip Y
                    row.arrow:SetTexCoord(0, 1, 1, 0) 
                else
                    -- DOWN (Expanded) -> Normal
                    row.arrow:SetTexCoord(0, 1, 0, 1)
                end
                
                row:SetScript("OnClick", function()
                    if data.isCollapsed then C_Reputation.ExpandFactionHeader(i) 
                    else C_Reputation.CollapseFactionHeader(i) end
                    AXIOM_Armory:UpdateReputation()
                end)
            else
                -- NESTED / CHILD STYLING
                row.text:SetPoint("LEFT", 25, 0) -- Level 1 (20px offset)
                row.bg:Hide()
                row.arrow:Hide()
                
                -- RENDER BAR
                row.bar:Show()
                local isMajor = C_Reputation.IsMajorFaction(data.factionID)
                
                if isMajor then
                    local renownData = C_MajorFactions.GetMajorFactionData(data.factionID)
                    if renownData then
                        local lvl = renownData.renownLevel
                        local cur = renownData.renownReputationEarned or 0
                        local max = renownData.renownLevelThreshold or 2500
                        local isCapped = C_MajorFactions.HasMaximumRenown(data.factionID)
                        
                        row.val:SetText("Renown " .. lvl .. " (" .. cur .. "/" .. max .. ")")
                        row.bar:SetMinMaxValues(0, max)
                        row.bar:SetValue(cur)
                        if isCapped then 
                            row.bar:SetValue(max); row.val:SetText("Renown " .. lvl .. " (Max)") 
                        end
                        row.bar:SetStatusBarColor(0, 0.8, 1, 0.5)
                    end
                else
                    local standingID = data.reaction
                    local barMin, barMax, barValue = data.currentReactionThreshold, data.nextReactionThreshold, data.currentStanding
                    local label = _G["FACTION_STANDING_LABEL"..standingID] or "Neutral"
                    local color = FACTION_BAR_COLORS[standingID] or {r=0.5, g=0.5, b=0.5}
                    
                    row.val:SetText(label .. " (" .. (barValue - barMin) .. "/" .. (barMax - barMin) .. ")")
                    row.bar:SetMinMaxValues(0, barMax - barMin)
                    row.bar:SetValue(barValue - barMin)
                    row.bar:SetStatusBarColor(color.r, color.g, color.b, 0.5)
                end
                
                row.wbIcon:SetPoint("LEFT", row.text, "RIGHT", 5, 0)
                row:SetScript("OnClick", OpenDetail)
            end
            
            row:Show()
            y = y + 20
        end
    end
    
    -- If the detailed faction wasn't found (e.g. collapsed header), close details
    if needsDetailRefresh and not foundActiveInUpdate then
        dFrame:Hide()
    end
    
    parent:SetHeight(y + 20)
end

function AXIOM_Armory:UpdateCurrency()
    local parent = self.CurrContent
    if not parent.rows then parent.rows = {} end
    for _, r in pairs(parent.rows) do r:Hide() end

    local y = 0
    local count = 0
    local listSize = C_CurrencyInfo.GetCurrencyListSize()
    
    for i = 1, listSize do
        local data = C_CurrencyInfo.GetCurrencyListInfo(i)
        if data then
            count = count + 1
            local row = parent.rows[count]
            if not row then
                row = CreateFrame("Button", nil, parent)
                row:SetSize(360, 20)
                
                -- BG for Headers
                row.bg = row:CreateTexture(nil, "BACKGROUND")
                row.bg:SetAllPoints()
                row.bg:SetColorTexture(0.3, 0.3, 0.3, 0.5)
                row.bg:Hide()
                
                -- Arrow for Headers
                row.arrow = row:CreateTexture(nil, "OVERLAY")
                row.arrow:SetSize(16, 16)
                row.arrow:SetPoint("RIGHT", -10, 0)
                row.arrow:SetTexture("Interface\\Buttons\\UI-SortArrow")
                row.arrow:Hide()

                row.text = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                -- Point set dynamically below
                
                row.val = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                row.val:SetPoint("RIGHT", -30, 0) -- Adjusted to make room for arrow if needed
                
                row.icon = row:CreateTexture(nil, "ARTWORK")
                row.icon:SetSize(16, 16)
                row.icon:Hide()

                row.wbIcon = row:CreateTexture(nil, "OVERLAY")
                row.wbIcon:SetSize(16, 16)
                row.wbIcon:SetAtlas("account-wide-icon", true)
                row.wbIcon:Hide()
                
                parent.rows[count] = row
            end
            
            row:SetPoint("TOPLEFT", 0, -y)
            row.text:SetText(data.name)
            
            -- RESET VISUALS
            row.icon:Hide()
            row.wbIcon:Hide()
            row.val:SetText("")
            row.arrow:Hide()
            row.bg:Hide()
            row:SetScript("OnClick", nil)
            
            if data.isHeader then
                row.text:SetPoint("LEFT", 5, 0)
                row.text:SetText(COLOR_GOLD .. data.name .. "|r")
                row.bg:Show()
                row.arrow:Show()
                
                if data.isHeaderExpanded then
                     row.arrow:SetTexCoord(0, 1, 0, 1) -- Down
                else
                     row.arrow:SetTexCoord(0, 1, 1, 0) -- Up
                end
                
                row:SetScript("OnClick", function()
                    if data.isHeaderExpanded then C_CurrencyInfo.ExpandCurrencyList(i, false)
                    else C_CurrencyInfo.ExpandCurrencyList(i, true) end
                    AXIOM_Armory:UpdateCurrency()
                end)
            else
                -- NESTED ROW
                row.text:SetPoint("LEFT", 45, 0) -- Indent + Space for Icon
                row.text:SetText(data.name)
                row.val:SetText(data.quantity)
                
                row.icon:SetTexture(data.iconFileID)
                row.icon:SetPoint("RIGHT", row.text, "LEFT", -5, 0)
                row.icon:Show()
                
                -- ROBUST ID FETCH (FIX: Bridge index to ID via Link)
                local link = C_CurrencyInfo.GetCurrencyListLink(i)
                local currencyID = link and C_CurrencyInfo.GetCurrencyIDFromLink(link)
                local info = currencyID and C_CurrencyInfo.GetCurrencyInfo(currencyID)
                
                -- Check Transferable using robust ID info if available, else fallback
                local isTransferable = info and info.isAccountTransferable
                
                if isTransferable then
                    row.wbIcon:Show()
                    row.wbIcon:SetPoint("LEFT", row.text, "RIGHT", 5, 0)
                end
                
                row:SetScript("OnClick", function()
                    AXIOM_Armory.CurrencyDetail:SetPoint("TOPRIGHT", row, "TOPLEFT", -5, 0)
                    AXIOM_Armory.CurrencyDetail.Icon:SetTexture(data.iconFileID)
                    AXIOM_Armory.CurrencyDetail.Name:SetText(data.name)
                    AXIOM_Armory.CurrencyDetail.Count:SetText("Total: " .. data.quantity)
                    
                    -- CRITICAL: FRESH FETCH ON CLICK
                    -- Ensure we have the latest server state when opening the detail window
                    local freshInfo = currencyID and C_CurrencyInfo.GetCurrencyInfo(currencyID)
                    
                    -- CRITICAL FIX: USE LIST DATA for the Backpack Checkbox, not just ID data
                    local freshListInfo = C_CurrencyInfo.GetCurrencyListInfo(i)
                    
                    if freshInfo and freshListInfo then
                        AXIOM_Armory.CurrencyDetail.Desc:SetText(freshInfo.description or "")
                        if freshInfo.maxQuantity > 0 then
                            AXIOM_Armory.CurrencyDetail.Count:SetText("Total: " .. data.quantity .. " / " .. freshInfo.maxQuantity)
                        end
                        
                        -- WARBAND TRANSFER LOGIC (PROTOCOL UPDATE: SAFE HELPER VIA CurrencyTransferMenu)
                        if freshInfo.isAccountTransferable then
                            AXIOM_Armory.CurrencyDetail.TransferBtn:Show()
                            AXIOM_Armory.CurrencyDetail.TransferBtn:SetPoint("TOPLEFT", AXIOM_Armory.CurrencyDetail.Desc, "BOTTOMLEFT", 0, -10)
                            
                            AXIOM_Armory.CurrencyDetail.TransferBtn:SetScript("OnClick", function()
                                OpenWarbandTransfer(currencyID) -- NEW HELPER FUNCTION
                                AXIOM_Armory.CurrencyDetail:Hide()
                            end)
                            
                            -- Position backpack check relative to Transfer
                            AXIOM_Armory.CurrencyDetail.BackpackCheck:SetPoint("TOPLEFT", AXIOM_Armory.CurrencyDetail.TransferBtn, "BOTTOMLEFT", 0, -5)
                        else
                            AXIOM_Armory.CurrencyDetail.TransferBtn:Hide()
                            -- Position backpack check relative to Desc (fallback)
                            AXIOM_Armory.CurrencyDetail.BackpackCheck:SetPoint("TOPLEFT", AXIOM_Armory.CurrencyDetail.Desc, "BOTTOMLEFT", 0, -10)
                        end
                        
                        -- BACKPACK TOGGLE LOGIC (FORCE RE-VERIFICATION)
                        -- Explicitly set Checked based on fresh LIST API return (reliable for checkboxes)
                        local isTracked = (freshListInfo.isShowInBackpack == true)
                        AXIOM_Armory.CurrencyDetail.BackpackCheck:SetChecked(isTracked)
                        
                        -- CRITICAL FIX: USE INDEX (i) INSTEAD OF ID FOR SETTING
                        -- AND FORCE NATIVE UI UPDATE
                        AXIOM_Armory.CurrencyDetail.BackpackCheck:SetScript("OnClick", function(self)
                            local isChecked = self:GetChecked()
                            C_CurrencyInfo.SetCurrencyBackpack(i, isChecked) -- USES LIST INDEX
                            
                            -- FORCE BACKPACK TOKEN FRAME UPDATE (Instant Visual Feedback)
                            if BackpackTokenFrame_Update then 
                                BackpackTokenFrame_Update() 
                            end
                        end)
                        AXIOM_Armory.CurrencyDetail.BackpackCheck:Show()
                        
                    else
                         AXIOM_Armory.CurrencyDetail.Desc:SetText("")
                         AXIOM_Armory.CurrencyDetail.TransferBtn:Hide()
                         AXIOM_Armory.CurrencyDetail.BackpackCheck:Hide()
                    end
                    
                    -- Dynamic Height
                    local descHeight = AXIOM_Armory.CurrencyDetail.Desc:GetStringHeight()
                    local baseHeight = 60 + descHeight -- For Icon, Name, Count, margins
                    if freshInfo then
                        baseHeight = baseHeight + 30 -- For BackpackCheck always
                        if freshInfo.isAccountTransferable then
                            baseHeight = baseHeight + 30 -- Extra for TransferBtn
                        end
                    end
                    AXIOM_Armory.CurrencyDetail:SetHeight(baseHeight + 20) -- Padding
                    
                    AXIOM_Armory.CurrencyDetail:Show()
                end)
            end
            
            row:Show()
            y = y + 20
        end
    end
    parent:SetHeight(y + 20)
end

-- =========================================================================
-- 4. CHARACTER STATS (MIDDLE) & TOOLTIP ENGINE
-- =========================================================================

local function AXIOM_ShowStatTooltip(self)
    local type = self.StatType
    local id = self.StatID
    
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:ClearLines()
    
    if type == "PRIMARY" or type == "STAMINA" then
        local stat, _, posBuff, negBuff = UnitStat("player", id)
        local statName = _G["SPELL_STAT"..id.."_NAME"]
        GameTooltip:SetText(statName)
        GameTooltip:AddLine(COLOR_WHITE .. stat .. "|r")
    elseif type == "SECONDARY" then
        local statName = self.Label:GetText()
        local desc = ENHANCEMENT_DESCRIPTIONS[id] or "No description available."
        GameTooltip:SetText(statName)
        GameTooltip:AddLine(desc, 1, 1, 1, true)
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Value: " .. self.Value:GetText(), 0.4, 0.8, 1)
    end
    GameTooltip:Show()
end

local function BuildStatsMiddle()
    local middle = CreateFrame("Frame", "AXIOM_Armory_Middle", AXIOM_Armory)
    middle:SetSize(250, FRAME_HEIGHT - HEADER_HEIGHT)
    middle:SetPoint("TOPLEFT", AXIOM_Armory, "TOPLEFT", 420, -HEADER_HEIGHT - 10) 

    local ilvlLabel = middle:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ilvlLabel:SetPoint("TOP", 0, -20); ilvlLabel:SetText("Item Level")
    
    local ilvlV = middle:CreateFontString("AXIOM_ILVL_TEXT", "OVERLAY", "GameFontNormalHuge")
    ilvlV:SetPoint("TOP", ilvlLabel, "BOTTOM", 0, -5); 
    
    AXIOM_Armory.StatsFrame = middle
end

-- =========================================================================
-- CLOSURE FACTORY & DATA MAPPING
-- =========================================================================

local function GetWidget(parent, key, type)
    if not parent.Widgets then parent.Widgets = {} end
    if not parent.Widgets[key] then
        local w
        if type == "ROW" then
            w = CreateFrame("Button", nil, parent)
            w:SetSize(200, 20)
            
            -- Create StatusBar (background layer)
            local bar = CreateFrame("StatusBar", nil, w)
            bar:SetAllPoints()
            bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
            bar:SetFrameLevel(w:GetFrameLevel() - 1)
            bar:SetMinMaxValues(0, 100)
            bar:SetValue(0)
            bar:SetStatusBarColor(0.2, 0.6, 1, 0.3)
            w.Bar = bar
            
            local t = w:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            t:SetPoint("LEFT", 0, 0)
            local v = w:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            v:SetPoint("RIGHT", 0, 0)
            w.Label = t; w.Value = v
        elseif type == "HEADER" then
            w = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal"); w:SetJustifyH("CENTER")
        elseif type == "SEPARATOR" then
            w = parent:CreateTexture(nil, "OVERLAY"); w:SetColorTexture(1, 0.82, 0, 0.5); w:SetSize(220, 1)
        elseif type == "SPACER" then
            w = CreateFrame("Frame", nil, parent); w:SetSize(1, 1) 
        end
        parent.Widgets[key] = w
    end
    return parent.Widgets[key]
end

local function GetDisplayValue(d)
    if d.type == "PRIMARY" or d.type == "STAMINA" then
        return (d.id and d.id > 0) and UnitStat("player", d.id) or "-"
    elseif d.type == "ARMOR" then
        local _, effArmor = UnitArmor("player")
        return effArmor
    elseif d.type == "SECONDARY" then
        local val = 0
        if d.id == 1 then val = GetCritChance()
        elseif d.id == 2 then val = GetHaste()
        elseif d.id == 3 then val = GetMasteryEffect()
        elseif d.id == 4 then val = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE)
        elseif d.id == 5 then val = GetLifesteal()
        elseif d.id == 6 then val = GetAvoidance()
        elseif d.id == 7 then val = GetSpeed() end
        return string.format("%.1f%%", val)
    end
    return "-"
end

local function AXIOM_CreateUpdateClosure(widget, d)
    return function()
        local displayVal = GetDisplayValue(d)
        widget.Value:SetText(displayVal)
        
        -- Update bar for SECONDARY stats
        if d.type == "SECONDARY" and widget.Bar then
            local numVal = tonumber(string.match(displayVal, "([%d%.]+)")) or 0
            local maxVal = (d.id <= 4) and 50 or 20  -- Primary stats cap ~50%, tertiary ~20%
            widget.Bar:SetMinMaxValues(0, maxVal)
            widget.Bar:SetValue(math.min(numVal, maxVal))
        end
    end
end

function AXIOM_Armory:RebuildStatRows()
    local middle = self.StatsFrame
    if not middle then return end
    if middle.Widgets then for _, w in pairs(middle.Widgets) do w:Hide() end end
    middle.ActiveUpdates = {} 

    local primaryStatID = 0
    local primaryStatName = "Primary"
    
    local currentSpec = GetSpecialization()
    if currentSpec then
        local _, _, _, _, _, pStat = GetSpecializationInfo(currentSpec)
        primaryStatID = pStat
        if pStat and pStat > 0 then primaryStatName = _G["SPELL_STAT"..pStat.."_NAME"] end
    end

    local layout = {
        { type = "HEADER", key = "HEAD_ATTR", text = "Attributes" },
        { type = "SPACER", key = "SPC_1", height = 5 },
        { type = "ROW", key = "ROW_PRIM", data = { type = "PRIMARY", id = primaryStatID, name = primaryStatName } },
        { type = "ROW", key = "ROW_ARMOR", data = { type = "ARMOR", id = -1, name = _G.STAT_ARMOR } },
        { type = "ROW", key = "ROW_STAM", data = { type = "STAMINA", id = 3, name = _G.SPELL_STAT3_NAME } },
        { type = "SPACER", key = "SPC_2", height = 10 },
        { type = "SEPARATOR", key = "SEP_LINE" },
        { type = "SPACER", key = "SPC_3", height = 10 },
        { type = "HEADER", key = "HEAD_ENH", text = "Enhancements" },
        { type = "SPACER", key = "SPC_4", height = 5 },
    }
    
    local secs = { "Crit", "Haste", "Mastery", "Versatility", "Leech", "Avoidance", "Speed" }
    for i, name in ipairs(secs) do
        table.insert(layout, { type = "ROW", key = "ROW_SEC_"..i, data = { type = "SECONDARY", id = i, name = name } })
    end

    local currentY = -70 
    for _, elem in ipairs(layout) do
        local w = GetWidget(middle, elem.key, elem.type)
        w:Show()
        if elem.type == "HEADER" then
            w:SetPoint("TOP", 0, currentY); w:SetText(COLOR_GOLD .. elem.text .. "|r"); currentY = currentY - 20
        elseif elem.type == "SEPARATOR" then
            w:SetPoint("TOP", 0, currentY); currentY = currentY - 2
        elseif elem.type == "SPACER" then
            currentY = currentY - (elem.height or 5)
        elseif elem.type == "ROW" then
            w:SetPoint("TOP", 0, currentY)
            w.Label:SetText(elem.data.name)
            w.StatType = elem.data.type; w.StatID = elem.data.id
            w:SetScript("OnEnter", AXIOM_ShowStatTooltip)
            w:SetScript("OnLeave", function() GameTooltip:Hide() end)
            local updateFunc = AXIOM_CreateUpdateClosure(w, elem.data)
            table.insert(middle.ActiveUpdates, updateFunc)
            currentY = currentY - 20
        end
    end
    self:UpdateStats()
end

-- =========================================================================
-- 5. AXIOM INTEL (RIGHT)
-- =========================================================================

local function BuildIntelRight()
    local right = CreateFrame("Frame", "AXIOM_Intel", AXIOM_Armory)
    right:SetSize(300, FRAME_HEIGHT - HEADER_HEIGHT)
    right:SetPoint("TOPLEFT", AXIOM_Armory, "TOPLEFT", 680, -HEADER_HEIGHT - 10) -- SHIFTED to 680
    AXIOM_Armory.Intel = right

    local scoreLabel = right:CreateFontString("AXIOM_Intel_Score", "OVERLAY", "GameFontNormalLarge")
    scoreLabel:SetPoint("TOP", 0, -20); scoreLabel:SetText("M+ Score: -")

    local raidHeader = right:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    raidHeader:SetPoint("TOP", 0, -50); raidHeader:SetText(COLOR_GOLD .. "Raid Progress|r")

    -- HEADERS for Raid Progress (N, H, M)
    local lblN = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblN:SetPoint("TOPLEFT", 35, -75); lblN:SetText(COLOR_GREY.."Norm|r")

    local lblH = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblH:SetPoint("TOPLEFT", 130, -75); lblH:SetText(COLOR_BLUE.."Hero|r")

    local lblM = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblM:SetPoint("TOPLEFT", 225, -75); lblM:SetText(COLOR_GOLD.."Myth|r")

    -- VALUES
    AXIOM_Armory.Intel.RaidNorm = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Armory.Intel.RaidNorm:SetPoint("TOPLEFT", 35, -90); AXIOM_Armory.Intel.RaidNorm:SetText("-")

    AXIOM_Armory.Intel.RaidHeroic = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Armory.Intel.RaidHeroic:SetPoint("TOPLEFT", 130, -90); AXIOM_Armory.Intel.RaidHeroic:SetText("-")

    AXIOM_Armory.Intel.RaidMythic = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Armory.Intel.RaidMythic:SetPoint("TOPLEFT", 225, -90); AXIOM_Armory.Intel.RaidMythic:SetText("-")

    AXIOM_Armory.Intel.DungeonStrings = {}
    for i, d in ipairs(DUNGEONS) do
        local row = math.floor((i-1)/2)
        local col = (i-1)%2
        local dFrame = CreateFrame("Frame", nil, right)
        
        -- CENTER FOLD CALCULATION:
        -- Panel Width: 300 | Gap: 35 | Frame Width: 90
        -- Total Content: 90 + 35 + 90 = 215
        -- Left Margin: (300 - 215) / 2 = 42.5
        
        dFrame:SetSize(90, 40)
        dFrame:SetPoint("TOPLEFT", 42.5 + (col*125), -170 - (row*50))
        
        local lbl = dFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        lbl:SetPoint("TOPLEFT", 0, 0); lbl:SetText(d.short)
        
        local valStr = dFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
        valStr:SetPoint("TOPLEFT", 0, -15); valStr:SetText("-")
        
        AXIOM_Armory.Intel.DungeonStrings[d.short] = valStr
    end
end

-- =========================================================================
-- 6. P2P ENGINE (RESPONDER ONLY)
-- =========================================================================

C_ChatInfo.RegisterAddonMessagePrefix("AXIOM_INS")

local function SerializeMyData()
    local rio = FetchRaiderIOData()
    local _, effArmor = UnitArmor("player")
    local spec = GetSpecialization()
    local pStatVal = 0
    if spec then
        local _, _, _, _, _, pStat = GetSpecializationInfo(spec)
        if pStat then pStatVal = UnitStat("player", pStat) end
    end
    
    local stats = {
        prim = pStatVal,
        stam = UnitStat("player", 3),
        armor = effArmor,
        crit = string.format("%.1f", GetCritChance()),
        haste = string.format("%.1f", GetHaste()),
        mast = string.format("%.1f", GetMasteryEffect()),
        vers = string.format("%.1f", GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE)),
        leech = string.format("%.1f", GetLifesteal()),
        avoid = string.format("%.1f", GetAvoidance()),
        speed = string.format("%.1f", GetSpeed())
    }
    
    local packet = table.concat({
        rio.score, rio.raidN, rio.raidH, rio.raidM,
        stats.prim, stats.stam, stats.armor,
        stats.crit, stats.haste, stats.mast, stats.vers, stats.leech, stats.avoid, stats.speed
    }, "^")
    
    local dunStr = "DUN:"
    for k,v in pairs(rio.dungeons) do dunStr = dunStr .. k .. "=" .. v .. "," end
    
    return packet .. "^" .. dunStr
end

local function OnComm(_, prefix, msg, channel, sender)
    if prefix ~= "AXIOM_INS" then return end
    if msg == "REQ" then
        local payload = SerializeMyData()
        C_ChatInfo.SendAddonMessage("AXIOM_INS", "DAT^" .. payload, "WHISPER", sender)
    end
end

function AXIOM_Armory:UpdateIntel()
    local data = FetchRaiderIOData()
    
    _G["AXIOM_Intel_Score"]:SetText("M+ Score: " .. GetRioColor(data.score) .. data.score .. "|r")
    
    if self.Intel.RaidNorm then 
        self.Intel.RaidNorm:SetText(GetProgColor(data.raidN) .. (data.raidN or "-") .. "|r")
    end
    if self.Intel.RaidHeroic then 
        self.Intel.RaidHeroic:SetText(GetProgColor(data.raidH) .. (data.raidH or "-") .. "|r")
    end
    if self.Intel.RaidMythic then 
        self.Intel.RaidMythic:SetText(GetProgColor(data.raidM) .. (data.raidM or "-") .. "|r")
    end

    for short, fontString in pairs(self.Intel.DungeonStrings) do
        local level = data.dungeons and data.dungeons[short] or 0
        local kColor = (level >= 12) and "|cffff8000" or (level >= 8 and "|cffa335ee" or "|cffffffff")
        fontString:SetText(kColor .. (level > 0 and "+"..level or "-") .. "|r")
    end
end

function AXIOM_Armory:UpdateStats()
    local _, ilvl = GetAverageItemLevel()
    -- Use full precision for display, can floor for color check (or just use value)
    local val = ilvl or 0
    
    if _G["AXIOM_ILVL_TEXT"] then
        -- Restore 2 decimals: %.2f
        _G["AXIOM_ILVL_TEXT"]:SetText(GetIlvlColor(val) .. string.format("%.2f", val) .. "|r")
    end

    if self.StatsFrame and self.StatsFrame.ActiveUpdates then
        for _, func in ipairs(self.StatsFrame.ActiveUpdates) do
            func()
        end
    end
end

function AXIOM_Armory:UpdateItems()
    local unit = "player"
    for id, btn in pairs(AXIOM_Armory.Slots) do
        local link = GetInventoryItemLink(unit, id)
        
        -- Reset ILVL Text by default
        btn.IlvlText:SetText("")
        
        if link then
            btn.icon:SetTexture(GetInventoryItemTexture(unit, id))
            
            -- ITEM LEVEL OVERLAY
            local actualIlvl = GetDetailedItemLevelInfo(link) or 0
            local colorCode = "|cffffffff" -- Default White (Quality)
            
            -- UPGRADE STATUS SCANNER
            -- Defaults: Green (<=4), Purple (<=7), Orange (8)
            -- If Not Upgradeable: Use Quality Color or White
            
            local currentUpgrade, maxUpgrade = 0, 0
            local data = C_TooltipInfo.GetInventoryItem(unit, id)
            if data and data.lines then
                for _, line in ipairs(data.lines) do
                    local txt = line.leftText
                    if txt then
                        local cur, max = string.match(txt, "Upgrade Level: .+ (%d+)/(%d+)")
                        if not cur then 
                            cur, max = string.match(txt, "(%d+)/(%d+)") -- Fallback simpler pattern
                        end
                        
                        if cur and max then
                            currentUpgrade = tonumber(cur)
                            maxUpgrade = tonumber(max)
                            break
                        end
                    end
                end
            end
            
            if maxUpgrade > 0 then
                if currentUpgrade == 8 then 
                    colorCode = "|cffff8000" -- Orange (Legendary)
                elseif currentUpgrade >= 5 then 
                    colorCode = "|cffa335ee" -- Purple
                else 
                    colorCode = "|cff00ff00" -- Green
                end
            else
                -- Fallback to Item Quality Color if not upgrade track
                local _, _, quality = GetItemInfo(link)
                if quality then
                    local _, _, _, hex = GetItemQualityColor(quality)
                    colorCode = "|c" .. hex
                end
            end
            
            btn.IlvlText:SetText(colorCode .. actualIlvl .. "|r")
            
            -- SLOT 17 (OFF-HAND) VISIBILITY CHECK
            if id == 17 and btn.ExpandBtn then
                local showExpand = false
                local _, _, _, itemEquipLoc = GetItemInfoInstant(link)
                
                -- Allowed Equipment Locations for Buffs (Weapons Only)
                local validLocs = {
                    ["INVTYPE_WEAPON"] = true,          -- One-Hand
                    ["INVTYPE_2HWEAPON"] = true,        -- Two-Hand (Titan's Grip)
                    ["INVTYPE_WEAPONMAINHAND"] = true,  -- Rare
                    ["INVTYPE_WEAPONOFFHAND"] = true    -- Off-hand Weapon
                }
                
                -- Hide if Shield or Held In Off-hand (Frills/Orbs)
                if validLocs[itemEquipLoc] then
                    showExpand = true
                end
                btn.ExpandBtn:SetShown(showExpand)
            end
            
        else 
            btn.icon:SetTexture("Interface\\PaperDoll\\UI-Backpack-EmptySlot")
            if btn.ExpandBtn then btn.ExpandBtn:Hide() end
        end
        
        btn.ExtraText:SetText("")
        if self.ShowExtras and link then
            local info = GetItemExtras(unit, id)
            if info then
                local txt = ""
                if info.enchant then 
                    txt = txt .. COLOR_GREEN .. info.enchant .. "|r\n" 
                end
                
                for _, statStr in ipairs(info.gems) do
                    txt = txt .. COLOR_BLUE .. statStr .. "|r\n"
                end
                
                if info.embellish then 
                    txt = txt .. COLOR_GOLD .. info.embellish .. "|r" 
                end
                btn.ExtraText:SetText(txt)
            end
        end
    end
end

function AXIOM_Armory:SetUnit(unit)
    -- GUARD CLAUSE: Prevent crash if UI not built
    if not self.Title then return end

    unit = "player"
    self.ViewingUnit = unit
    self.Title:SetText(COLOR_BLUE .. "A.X.I.O.M.|r | ARMORY")
    _G["AXIOM_PlayerModel"]:SetUnit("player")
    
    self.NameStr:SetText(UnitName("player"))
    
    -- Guild
    local guildName = GetGuildInfo("player")
    if guildName then
        self.GuildStr:SetText(COLOR_GREEN .. "<" .. guildName .. ">|r")
    else
        self.GuildStr:SetText("")
    end
    
    -- Details (Level Class - Spec)
    local lvl = UnitLevel("player")
    local localizedClass, englishClass = UnitClass("player")
    local specIndex = GetSpecialization()
    local specID, specName = 0, ""
    
    if specIndex then
        specID, specName = GetSpecializationInfo(specIndex)
    end
    
    local classColor = C_ClassColor.GetClassColor(englishClass)
    local classColorStr = classColor and classColor:GenerateHexColorMarkup() or "|cffffffff"
    local specColorStr = GetSpecColor(specID, englishClass)
    
    local detailText = string.format("%s %s%s|r - %s%s|r", lvl, classColorStr, localizedClass, specColorStr, specName or "")
    self.DetailStr:SetText(detailText)
    
    self:RebuildStatRows()
    self:UpdateItems()
    self:UpdateIntel()
    self:UpdateStats()
end

-- =========================================================================
-- 7. EVENTS & HOOKS
-- =========================================================================

local function OnEvent(self, event, ...)
    if event == "PLAYER_LOGIN" then
        BuildReskin()
        BuildArmoryLeft()
        BuildStatsMiddle()
        BuildIntelRight()
        
        if CharacterFrame then
             CharacterFrame:HookScript("OnShow", function()
                 if AXIOM_System_Enabled then
                     AXIOM_Armory:SetUnit("player")
                     AXIOM_Armory:Show()
                     SterilizeNativeUI()
                 end
             end)
        end
        
        self:SetUnit("player")
        
    elseif event == "CHAT_MSG_ADDON" then
        OnComm(self, ...)

    -- Added CURRENCY_DISPLAY_UPDATE to ensure sync with server pushes
    elseif event == "PLAYER_EQUIPMENT_CHANGED" or event == "PLAYER_AVG_ITEM_LEVEL_UPDATE" or event == "PLAYER_GUILD_UPDATE" or event == "UPDATE_FACTION" or event == "CURRENCY_DISPLAY_UPDATE" then
        self:SetUnit("player") -- Refreshes all
    end
end

AXIOM_Armory:RegisterEvent("PLAYER_LOGIN")
AXIOM_Armory:RegisterEvent("CHAT_MSG_ADDON")
AXIOM_Armory:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
AXIOM_Armory:RegisterEvent("PLAYER_AVG_ITEM_LEVEL_UPDATE")
AXIOM_Armory:RegisterEvent("PLAYER_GUILD_UPDATE")
AXIOM_Armory:RegisterEvent("UPDATE_FACTION") 
AXIOM_Armory:RegisterEvent("CURRENCY_DISPLAY_UPDATE") -- Registered Event
AXIOM_Armory:SetScript("OnEvent", OnEvent)