local _, WN = ...

local function SetRowItemTooltip(row, link)
    row.itemLink = link
    if link then
        row:SetScript("OnEnter", function(self)
            self:SetBackdropColor(unpack(WN.colors.panelHover))
            if not WN.db or WN.db.settings.privateTooltips ~= false then
                local tip = WN:PrepareHoverTooltip(self, "ANCHOR_RIGHT")
                tip:SetHyperlink(self.itemLink)
                tip:Show()
            end
        end)
        row:SetScript("OnLeave", function(self)
            self:SetBackdropColor(unpack(WN.colors.panel))
            WN:HideHoverTooltip()
        end)
    else
        row:SetScript("OnEnter", function(self) self:SetBackdropColor(unpack(WN.colors.panelHover)) end)
        row:SetScript("OnLeave", function(self) self:SetBackdropColor(unpack(WN.colors.panel)) end)
    end
end

local function GetQualityColor(quality)
    if quality and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality] then
        local c = ITEM_QUALITY_COLORS[quality]
        return c.r, c.g, c.b
    end
    return unpack(WN.colors.text)
end

local function MakeSmallLine(panel, y, icon, label)
    local row = CreateFrame("Frame", nil, panel)
    row:SetPoint("TOPLEFT", 10, y)
    row:SetPoint("TOPRIGHT", -10, y)
    row:SetHeight(30)
    row.icon = row:CreateTexture(nil, "ARTWORK")
    row.icon:SetSize(18, 18)
    row.icon:SetPoint("LEFT", 0, 0)
    row.icon:SetTexture(icon or WN.icons.info)
    row.label = WN:CreateText(row, 10, WN.colors.text, "LEFT")
    row.label:SetPoint("LEFT", 26, 0)
    row.label:SetText(label or "")
    row.value = WN:CreateText(row, 9, WN.colors.muted, "RIGHT")
    row.value:SetPoint("RIGHT", 0, 0)
    return row
end

function WN:CreateOverviewSection(parent)
    local page = CreateFrame("Frame", nil, parent)
    page:SetAllPoints()
    self.sections.overview = page

    local w, gap, topH = 286, 10, 220
    page.weekly = self:CreatePanel(page, self:T("WEEKLY_PROGRESS"), w, topH)
    page.weekly:SetPoint("TOPLEFT", 0, 0)
    page.upgrades = self:CreatePanel(page, self:T("NEXT_UPGRADE"), w, topH)
    page.upgrades:SetPoint("TOPLEFT", page.weekly, "TOPRIGHT", gap, 0)
    page.currencies = self:CreatePanel(page, self:T("CURRENCIES"), w, topH)
    page.currencies:SetPoint("TOPLEFT", page.upgrades, "TOPRIGHT", gap, 0)

    page.weekly.rows = {}
    local weekDefs = {
        { key = "MYTHIC_PLUS", icon = self.icons.mythic },
        { key = "RAID", icon = self.icons.raid },
        { key = "DELVES_WORLD", icon = self.icons.delves },
        { key = "PVP", icon = self.icons.pvp },
        { key = "REPUTATION", icon = self.icons.reputation },
    }
    for i, def in ipairs(weekDefs) do
        local row = CreateFrame("Frame", nil, page.weekly)
        row:SetPoint("TOPLEFT", 10, -38 - (i - 1) * 34)
        row:SetPoint("TOPRIGHT", -10, -38 - (i - 1) * 34)
        row:SetHeight(30)
        row.icon = row:CreateTexture(nil, "ARTWORK")
        row.icon:SetSize(18,18)
        row.icon:SetPoint("LEFT",0,4)
        row.icon:SetTexture(def.icon)
        row.label = self:CreateText(row, 10, self.colors.text, "LEFT")
        row.label:SetPoint("LEFT", 26, 5)
        row.label:SetWidth(82)
        row.label:SetText(self:T(def.key))
        row.bar = self:CreateProgressBar(row, 112, 12)
        row.bar:SetPoint("LEFT", 106, 4)
        row.count = self:CreateText(row, 9, self.colors.text, "RIGHT")
        row.count:SetPoint("RIGHT", 0, 4)
        row.count:SetWidth(42)
        row.key = def.key
        page.weekly.rows[def.key] = row
    end

    page.upgrades.rows = {}
    for i = 1, 3 do
        local row = self:CreateIconRow(page.upgrades, 264, 48)
        row:SetPoint("TOPLEFT", 10, -40 - (i - 1) * 54)
        page.upgrades.rows[i] = row
    end
    page.upgrades.note = self:CreateText(page.upgrades, 8, self.colors.faint, "LEFT")
    page.upgrades.note:SetPoint("BOTTOMLEFT", 10, 7)
    page.upgrades.note:SetPoint("BOTTOMRIGHT", -10, 7)
    page.upgrades.note:SetText(self:T("UPGRADE_NOTE"))

    page.currencies.rows = {}
    for i = 1, 5 do
        local row = MakeSmallLine(page.currencies, -38 - (i - 1) * 33, self.icons.info, "")
        page.currencies.rows[i] = row
    end

    local bottomY, bottomH = -232, 238
    page.instances = self:CreatePanel(page, self:T("INSTANCES"), 258, bottomH)
    page.instances:SetPoint("TOPLEFT", 0, bottomY)
    page.professions = self:CreatePanel(page, self:T("PROFESSIONS"), 200, bottomH)
    page.professions:SetPoint("TOPLEFT", page.instances, "TOPRIGHT", gap, 0)
    page.collection = self:CreatePanel(page, self:T("COLLECTION"), 190, bottomH)
    page.collection:SetPoint("TOPLEFT", page.professions, "TOPRIGHT", gap, 0)
    page.quick = self:CreatePanel(page, self:T("QUICK_ACCESS"), 208, bottomH)
    page.quick:SetPoint("TOPLEFT", page.collection, "TOPRIGHT", gap, 0)

    page.instances.rows = {}
    for i = 1, 4 do
        local row = self:CreateIconRow(page.instances, 236, 42)
        row:SetPoint("TOPLEFT", 10, -40 - (i - 1) * 46)
        page.instances.rows[i] = row
    end

    page.professions.rows = {}
    for i = 1, 2 do
        local row = self:CreateIconRow(page.professions, 178, 48)
        row:SetPoint("TOPLEFT", 10, -40 - (i - 1) * 54)
        page.professions.rows[i] = row
    end
    page.professions.rep = MakeSmallLine(page.professions, -154, self.icons.reputation, self:T("REPUTATION"))
    page.professions.repBar = self:CreateProgressBar(page.professions, 168, 12)
    page.professions.repBar:SetPoint("BOTTOMLEFT", 10, 12)

    page.collection.rows = {}
    local collectionDefs = {
        { key = "MOUNTS", icon = self.icons.mount }, { key = "PETS", icon = self.icons.pet },
        { key = "APPEARANCES", icon = self.icons.transmog }, { key = "ACHIEVEMENTS", icon = self.icons.achievement },
    }
    for i, def in ipairs(collectionDefs) do
        local row = MakeSmallLine(page.collection, -40 - (i - 1) * 45, def.icon, self:T(def.key))
        row.key = def.key
        page.collection.rows[def.key] = row
    end

    local quickDefs = {
        { "GROUP_FINDER", "group", self.icons.group }, { "CALENDAR", "calendar", self.icons.calendar },
        { "AUCTION_HOUSE", "auction", self.icons.auction }, { "COLLECTIONS", "collections", self.icons.collections },
        { "LOCATIONS", "locations", self.icons.locations }, { "WORK_ORDERS", "workorders", self.icons.profession },
        { "ADVENTURE_GUIDE", "adventure", self.icons.info }, { "TALENTS", "talents", self.icons.talents },
    }
    page.quick.buttons = {}
    for i, def in ipairs(quickDefs) do
        local col = (i - 1) % 2
        local row = math.floor((i - 1) / 2)
        local button = self:CreateIconButton(page.quick, 88, 43, def[3], self:T(def[1]), nil)
        button.action = def[2]; button.textKey = def[1]
        button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
        button:SetScript("OnClick", function(btn, mouseButton)
            if mouseButton == "RightButton" then WN:ToggleFavorite(btn.action, WN:T(btn.textKey)) else WN:OpenTool(btn.action) end
        end)
        button:SetPoint("TOPLEFT", 10 + col * 98, -40 - row * 47)
        button._wnOriginalIndex = i
        page.quick.buttons[i] = button
    end
end

function WN:UpdateOverviewSection(data)
    local page = self.sections.overview
    if not page then return end
    local weekly = data.weekly
    for key, row in pairs(page.weekly.rows) do
        if key == "REPUTATION" then
            local rep = data.reputation
            if rep and rep.maximum > 0 then
                self:SetProgress(row.bar, rep.current, rep.maximum, "")
                row.count:SetText(self:FormatNumber(rep.current) .. "/" .. self:FormatNumber(rep.maximum))
                row.label:SetText(rep.name)
            else
                self:SetProgress(row.bar, 0, 1, "")
                row.count:SetText(self:T("NA"))
                row.label:SetText(self:T("REPUTATION"))
            end
        else
            local group = weekly.groups[key]
            if group and group.threshold > 0 then
                self:SetProgress(row.bar, group.progress, group.threshold, "")
                row.count:SetText(group.progress .. "/" .. group.threshold)
            else
                self:SetProgress(row.bar, 0, 1, "")
                row.count:SetText(self:T("NA"))
            end
        end
    end

    for i, row in ipairs(page.upgrades.rows) do
        local item = data.equipment.upgradeCandidates[i]
        if item then
            row:Show()
            row.icon:SetTexture(item.icon or self.icons.gear)
            row.name:SetText(item.name)
            local r,g,b = GetQualityColor(item.quality)
            row.name:SetTextColor(r,g,b)
            row.meta:SetText(item.slotName)
            row.right:SetText(string.format("%.0f → %s", item.itemLevel, self:T("CHECK")))
            SetRowItemTooltip(row, item.link)
        else
            row:Hide()
        end
    end

    for i, row in ipairs(page.currencies.rows) do
        local c = data.currencies.currencies[i]
        if c then
            row:Show()
            row.icon:SetTexture(c.icon or self.icons.info)
            row.label:SetText(c.name)
            row.value:SetText(self:FormatNumber(c.quantity))
        else
            row:Hide()
        end
    end
    if #data.currencies.currencies == 0 then
        local row = page.currencies.rows[1]
        row:Show(); row.icon:SetTexture(self.icons.auction); row.label:SetText(self:T("GOLD")); row.value:SetText(self:FormatMoney(data.currencies.money))
    end

    for i, row in ipairs(page.instances.rows) do
        local inst = data.instances[i]
        if inst then
            row:Show()
            row.icon:SetTexture(inst.isRaid and self.icons.raid or self.icons.mythic)
            row.name:SetText(inst.name)
            local progress = inst.encounters > 0 and (inst.completed .. "/" .. inst.encounters) or inst.difficultyName
            row.meta:SetText(inst.difficultyName)
            row.right:SetText(progress)
            row:SetScript("OnClick", function() WN:OpenTool("adventure") end)
        else
            row:Hide()
        end
    end
    if #data.instances == 0 then
        local row = page.instances.rows[1]
        row:Show(); row.icon:SetTexture(self.icons.check); row.name:SetText(self:T("NO_SAVED_INSTANCES")); row.meta:SetText(""); row.right:SetText("")
    end

    for i, row in ipairs(page.professions.rows) do
        local prof = data.professions.professions[i]
        if prof then
            row:Show(); row.icon:SetTexture(prof.icon or self.icons.profession); row.name:SetText(prof.name)
            row.meta:SetText(prof.skill .. "/" .. prof.maxSkill); row.right:SetText(prof.modifier > 0 and ("+" .. prof.modifier) or "")
            row:SetScript("OnClick", function() WN:OpenTool("professions") end)
        else
            row:Hide()
        end
    end
    local rep = data.reputation
    if rep and rep.maximum > 0 then
        page.professions.rep.label:SetText(rep.name)
        page.professions.rep.value:SetText(rep.current .. "/" .. rep.maximum)
        self:SetProgress(page.professions.repBar, rep.current, rep.maximum, "")
    else
        page.professions.rep.label:SetText(self:T("REPUTATION"))
        page.professions.rep.value:SetText(self:T("NA"))
        self:SetProgress(page.professions.repBar, 0, 1, "")
    end

    page.collection.rows.MOUNTS.value:SetText(data.collections.mounts.collected .. "/" .. data.collections.mounts.total)
    page.collection.rows.PETS.value:SetText(data.collections.pets.collected .. "/" .. data.collections.pets.total)
    page.collection.rows.APPEARANCES.value:SetText(data.collections.appearances.collected .. "/" .. data.collections.appearances.total)
    page.collection.rows.ACHIEVEMENTS.value:SetText(self:FormatNumber(data.collections.achievementPoints))
    local ordered = {}
    for index,button in ipairs(page.quick.buttons or {}) do
        button._wnOriginalIndex = button._wnOriginalIndex or index
        ordered[#ordered + 1] = button
    end
    table.sort(ordered, function(a,b)
        local af = self.db.settings.showFavorites ~= false and self:IsFavorite(a.action)
        local bf = self.db.settings.showFavorites ~= false and self:IsFavorite(b.action)
        if af ~= bf then return af end
        return (a._wnOriginalIndex or 99) < (b._wnOriginalIndex or 99)
    end)
    for index,button in ipairs(ordered) do
        local favorite = self.db.settings.showFavorites ~= false and self:IsFavorite(button.action)
        button.label:SetText((favorite and "★ " or "") .. self:T(button.textKey))
        button:SetBackdropBorderColor(unpack(favorite and self.colors.accent or self.colors.borderSoft))
        local col=(index-1)%2; local rr=math.floor((index-1)/2)
        button:ClearAllPoints(); button:SetPoint("TOPLEFT",10+col*98,-40-rr*47)
    end
end

function WN:CreateCharacterSection(parent)
    local page = CreateFrame("Frame", nil, parent)
    page:SetAllPoints()
    self.sections.character = page
    self:CreateSectionHeader(page)

    page.left = self:CreatePanel(page, "", 248, 430)
    page.left:SetPoint("TOPLEFT", 0, -48)
    page.center = self:CreatePanel(page, "", 356, 430)
    page.center:SetPoint("TOPLEFT", page.left, "TOPRIGHT", 10, 0)
    page.right = self:CreatePanel(page, "", 248, 430)
    page.right:SetPoint("TOPLEFT", page.center, "TOPRIGHT", 10, 0)
    page.left.title:Hide(); page.left.rule:Hide(); page.center.title:Hide(); page.center.rule:Hide(); page.right.title:Hide(); page.right.rule:Hide()

    page.left.rows = {}; page.right.rows = {}
    for i = 1, 8 do
        local l = self:CreateIconRow(page.left, 226, 46); l:SetPoint("TOPLEFT", 10, -10 - (i - 1) * 51); page.left.rows[i] = l
        local r = self:CreateIconRow(page.right, 226, 46); r:SetPoint("TOPLEFT", 10, -10 - (i - 1) * 51); page.right.rows[i] = r
    end

    page.center.model = CreateFrame("PlayerModel", nil, page.center)
    page.center.model:SetPoint("TOPLEFT", 10, -10)
    page.center.model:SetPoint("BOTTOMRIGHT", -10, 88)
    page.center.model.facing = 0
    page.center.model:EnableMouse(true)
    local function UpdateModelRotation(self)
        local x = GetCursorPosition()
        local delta = x - (self.lastX or x)
        self.lastX = x
        self.facing = (self.facing or 0) + delta * 0.01
        if type(self.SetFacing) == "function" then self:SetFacing(self.facing) end
    end
    page.center.model:SetScript("OnMouseDown", function(self)
        self.dragging = true
        self.lastX = GetCursorPosition()
        self:SetScript("OnUpdate", UpdateModelRotation)
    end)
    page.center.model:SetScript("OnMouseUp", function(self)
        self.dragging = false
        self:SetScript("OnUpdate", nil)
    end)
    page.center.name = self:CreateText(page.center, 18, self.colors.text, "CENTER")
    page.center.name:SetPoint("BOTTOM", 0, 56)
    page.center.meta = self:CreateText(page.center, 10, self.colors.muted, "CENTER")
    page.center.meta:SetPoint("TOP", page.center.name, "BOTTOM", 0, -4)
    page.center.rating = self:CreateText(page.center, 10, self.colors.accent, "CENTER")
    page.center.rating:SetPoint("BOTTOM", 0, 14)
end

function WN:UpdateCharacterSection(data)
    local page = self.sections.character
    if not page then return end
    page.headerTitle:SetText(self:T("CHARACTER_TITLE")); page.headerSub:SetText(self:T("CHARACTER_SUB"))
    page.center.name:SetText(data.character.name)
    page.center.meta:SetText(self:T("LEVEL_SPEC", data.character.level, data.character.specName, data.character.zone))
    page.center.rating:SetText(self:T("RATING") .. ": " .. self:FormatNumber(data.character.mythicRating))
    if page.center.model and type(page.center.model.SetUnit) == "function" then self:SafeCall(page.center.model.SetUnit, page.center.model, "player") end

    for i = 1, 8 do
        local leftItem = data.equipment.items[i]
        local rightItem = data.equipment.items[i + 8]
        for row, item in pairs({ [page.left.rows[i]] = leftItem, [page.right.rows[i]] = rightItem }) do
            if item then
                row:Show(); row.icon:SetTexture(item.icon or self.icons.gear); row.name:SetText(item.slotName)
                local name = item.link and item.name or self:T("EMPTY")
                row.meta:SetText(name)
                row.right:SetText(item.itemLevel > 0 and tostring(math.floor(item.itemLevel + 0.5)) or "")
                local r,g,b = GetQualityColor(item.quality); row.meta:SetTextColor(r,g,b)
                SetRowItemTooltip(row, item.link)
            else row:Hide() end
        end
    end
end

function WN:CreateGearSection(parent)
    local page = CreateFrame("Frame", nil, parent); page:SetAllPoints(); self.sections.gear = page; self:CreateSectionHeader(page)
    page.cards = {}
    local defs = { "EQUIPPED_ILVL", "GEAR_CHECK", "MISSING_ENCHANTS", "EMPTY_SOCKETS" }
    for i, key in ipairs(defs) do
        local card = self:CreatePanel(page, self:T(key), 209, 86)
        card:SetPoint("TOPLEFT", (i - 1) * 219, -48)
        card.value = self:CreateText(card, 24, self.colors.text, "CENTER"); card.value:SetPoint("CENTER", 0, -10)
        page.cards[key] = card
    end
    page.status = self:CreatePanel(page, self:T("GEAR_STATUS"), 276, 336); page.status:SetPoint("TOPLEFT", 0, -144)
    page.status.score = self:CreateText(page.status, 34, self.colors.accent, "CENTER"); page.status.score:SetPoint("TOP", 0, -54)
    page.status.bar = self:CreateProgressBar(page.status, 244, 15); page.status.bar:SetPoint("TOP", 0, -103)
    page.status.message = self:CreateText(page.status, 10, self.colors.muted, "LEFT"); page.status.message:SetPoint("TOPLEFT", 16, -138); page.status.message:SetPoint("RIGHT", -16, 0); page.status.message:SetHeight(52)
    page.status.openCharacter = self:CreateButton(page.status, 116, 32, self:T("CHARACTER"), function() WN:OpenTool("character") end); page.status.openCharacter:SetPoint("BOTTOMLEFT", 14, 14)
    page.status.openVault = self:CreateButton(page.status, 116, 32, self:T("GREAT_VAULT"), function() WN:OpenTool("vault") end); page.status.openVault:SetPoint("BOTTOMRIGHT", -14, 14)

    page.items = self:CreatePanel(page, self:T("GEAR"), 586, 336); page.items:SetPoint("TOPLEFT", page.status, "TOPRIGHT", 10, 0)
    page.items.rows = {}
    for i = 1, 16 do
        local col = (i - 1) % 2; local rr = math.floor((i - 1) / 2)
        local row = self:CreateIconRow(page.items, 276, 34)
        row.icon:SetSize(24,24); row.name:SetPoint("LEFT", row.icon, "RIGHT", 6, 5); row.meta:SetPoint("LEFT", row.icon, "RIGHT", 6, -8)
        row:SetPoint("TOPLEFT", 10 + col * 288, -40 - rr * 36)
        page.items.rows[i] = row
    end
end

function WN:UpdateGearSection(data)
    local page = self.sections.gear; if not page then return end
    page.headerTitle:SetText(self:T("GEAR_STATUS")); page.headerSub:SetText(self:T("UPGRADE_NOTE"))
    page.cards.EQUIPPED_ILVL.value:SetText(string.format("%.1f", data.character.equippedItemLevel or 0))
    page.cards.GEAR_CHECK.value:SetText(data.equipment.score .. "%")
    page.cards.MISSING_ENCHANTS.value:SetText(tostring(data.equipment.missingEnchants))
    page.cards.EMPTY_SOCKETS.value:SetText(tostring(data.equipment.emptySockets))
    page.status.score:SetText(data.equipment.score .. "%")
    self:SetProgress(page.status.bar, data.equipment.score, 100, "")
    page.status.message:SetText(data.equipment.complete and self:T("GEAR_COMPLETE") or self:T("GEAR_INCOMPLETE"))
    page.status.score:SetTextColor(unpack(data.equipment.complete and self.colors.green or self.colors.yellow))

    for i, row in ipairs(page.items.rows) do
        local item = data.equipment.items[i]
        if item then
            row:Show(); row.icon:SetTexture(item.icon or self.icons.gear); row.name:SetText(item.slotName)
            local status = item.status == "missing" and self:T("EMPTY") or item.status == "warning" and self:T("WARNING") or item.status == "optional" and self:T("OPTIONAL") or self:T("OK")
            row.meta:SetText(item.link and item.name or status); row.right:SetText(item.itemLevel > 0 and tostring(math.floor(item.itemLevel + 0.5)) or status)
            local r,g,b = GetQualityColor(item.quality); row.meta:SetTextColor(r,g,b)
            if item.status == "warning" or item.status == "missing" then row:SetBackdropBorderColor(unpack(self.colors.yellow)) else row:SetBackdropBorderColor(unpack(self.colors.borderSoft)) end
            SetRowItemTooltip(row, item.link)
        else row:Hide() end
    end
end

function WN:CreateActivitiesSection(parent)
    local page = CreateFrame("Frame", nil, parent); page:SetAllPoints(); self.sections.activities = page; self:CreateSectionHeader(page)
    page.weekly = self:CreatePanel(page, self:T("GREAT_VAULT"), 330, 205); page.weekly:SetPoint("TOPLEFT", 0, -48)
    page.weekly.rows = {}
    for i, key in ipairs({"MYTHIC_PLUS","RAID","DELVES_WORLD","PVP"}) do
        local row = MakeSmallLine(page.weekly, -40 - (i-1)*38, self.icons[string.lower(key)] or self.icons.mythic, self:T(key))
        row.bar = self:CreateProgressBar(row, 124, 10); row.bar:SetPoint("RIGHT", -44, 0); row.value:SetWidth(42); row.key = key
        page.weekly.rows[key] = row
    end

    page.season = self:CreatePanel(page, self:T("SEASON_2"), 532, 205); page.season:SetPoint("TOPLEFT", page.weekly, "TOPRIGHT", 10, 0)
    page.season.raid = MakeSmallLine(page.season, -40, self.icons.raid, self:T("SEASON_RAID"))
    page.season.zone = MakeSmallLine(page.season, -76, self.icons.map, self:T("SEASON_ZONE"))
    page.season.delves = MakeSmallLine(page.season, -112, self.icons.delves, self:T("SEASON_DELVES"))
    page.season.note = self:CreateText(page.season, 8, self.colors.faint, "LEFT"); page.season.note:SetPoint("BOTTOMLEFT", 10, 10); page.season.note:SetPoint("RIGHT", -10, 0); page.season.note:SetText(self:T("SEASON_SOURCE_NOTE"))

    page.rotation = self:CreatePanel(page, self:T("CURRENT_MPLUS"), 430, 217); page.rotation:SetPoint("TOPLEFT", 0, -265)
    page.rotation.rows = {}
    for i = 1, 8 do
        local col=(i-1)%2; local rr=math.floor((i-1)/2)
        local row = MakeSmallLine(page.rotation, -40 - rr*40, self.icons.mythic, "")
        row:ClearAllPoints(); row:SetPoint("TOPLEFT", 10 + col*205, -40 - rr*40); row:SetSize(195,34); row.value:Hide()
        page.rotation.rows[i]=row
    end

    page.saved = self:CreatePanel(page, self:T("SAVED_CONTENT"), 432, 217); page.saved:SetPoint("TOPLEFT", page.rotation, "TOPRIGHT", 10, 0)
    page.saved.rows = {}
    for i=1,4 do local row=self:CreateIconRow(page.saved,410,38); row:SetPoint("TOPLEFT",10,-40-(i-1)*42); page.saved.rows[i]=row end
    page.saved.next = self:CreateText(page.saved, 9, self.colors.accent, "LEFT"); page.saved.next:SetPoint("BOTTOMLEFT",10,9); page.saved.next:SetPoint("RIGHT",-10,0)
end

function WN:UpdateActivitiesSection(data)
    local page=self.sections.activities; if not page then return end
    page.headerTitle:SetText(self:T("ACTIVITIES_TITLE")); page.headerSub:SetText(self:T("ACTIVITIES_SUB"))
    for key,row in pairs(page.weekly.rows) do
        local group=data.weekly.groups[key]
        if group and group.threshold>0 then self:SetProgress(row.bar,group.progress,group.threshold,""); row.value:SetText(group.progress.."/"..group.threshold) else self:SetProgress(row.bar,0,1,""); row.value:SetText(self:T("NA")) end
    end
    page.season.raid.value:SetText(self:T("RAID")); page.season.zone.value:SetText(self:T("SEASON")); page.season.delves.value:SetText(self:T("DELVES_WORLD"))
    for i,entry in ipairs(self.season2.mythicPlus) do page.rotation.rows[i].label:SetText(self:GetSeasonDungeonName(entry)) end
    for i,row in ipairs(page.saved.rows) do
        local inst=data.instances[i]
        if inst then row:Show(); row.icon:SetTexture(inst.isRaid and self.icons.raid or self.icons.mythic); row.name:SetText(inst.name); row.meta:SetText(inst.difficultyName); row.right:SetText(inst.encounters>0 and (inst.completed.."/"..inst.encounters) or self:FormatDuration(inst.reset)) else row:Hide() end
    end
    local nextText
    if not data.equipment.complete then nextText=self:T("NEXT_STEP_GEAR")
    else
        for _,key in ipairs({"MYTHIC_PLUS","RAID","DELVES_WORLD","PVP"}) do local g=data.weekly.groups[key]; if g and g.threshold>0 and g.progress<g.threshold then nextText=self:T("NEXT_STEP_WEEKLY",self:T(key)); break end end
    end
    page.saved.next:SetText(self:T("NEXT_STEP")..": "..(nextText or self:T("NEXT_STEP_FREE")))
end

function WN:CreateCollectionsSection(parent)
    local page=CreateFrame("Frame",nil,parent); page:SetAllPoints(); self.sections.collections=page; self:CreateSectionHeader(page)
    page.cards={}
    local defs={{"MOUNTS",self.icons.mount,"mounts"},{"PETS",self.icons.pet,"pets"},{"TOYS",self.icons.toy,"toys"},{"APPEARANCES",self.icons.transmog,"appearances"},{"ACHIEVEMENTS",self.icons.achievement,"achievements"}}
    for i,def in ipairs(defs) do
        local card=self:CreatePanel(page,self:T(def[1]),164,150); card:SetPoint("TOPLEFT",(i-1)*174,-48); card.icon=card:CreateTexture(nil,"ARTWORK"); card.icon:SetSize(40,40); card.icon:SetPoint("TOP",0,-44); card.icon:SetTexture(def[2]); card.value=self:CreateText(card,17,self.colors.text,"CENTER"); card.value:SetPoint("TOP",card.icon,"BOTTOM",0,-8); card.meta=self:CreateText(card,9,self.colors.muted,"CENTER"); card.meta:SetPoint("TOP",card.value,"BOTTOM",0,-2); card.kind=def[3]; page.cards[def[3]]=card
    end
    page.progress=self:CreatePanel(page,self:T("COLLECTIONS_TITLE"),686,268); page.progress:SetPoint("TOPLEFT",0,-210); page.progress.rows={}
    local pdefs={{"MOUNTS","mounts",self.icons.mount},{"PETS","pets",self.icons.pet},{"TOYS","toys",self.icons.toy},{"APPEARANCES","appearances",self.icons.transmog}}
    for i,def in ipairs(pdefs) do
        local row=MakeSmallLine(page.progress,-42-(i-1)*52,def[3],self:T(def[1])); row.bar=self:CreateProgressBar(row,350,12); row.bar:SetPoint("LEFT",170,0); row.value:SetWidth(100); row.kind=def[2]; page.progress.rows[def[2]]=row
    end
    page.actions=self:CreatePanel(page,self:T("QUICK_ACCESS"),176,268); page.actions:SetPoint("TOPLEFT",page.progress,"TOPRIGHT",10,0)
    local actions={{"MOUNTS","mounts",self.icons.mount},{"PETS","pets",self.icons.pet},{"TOYS","toys",self.icons.toy},{"APPEARANCES","appearances",self.icons.transmog},{"ACHIEVEMENTS","achievements",self.icons.achievement}}
    for i,def in ipairs(actions) do local b=self:CreateButton(page.actions,154,34,self:T(def[1]),function() WN:OpenTool(def[2]) end); b:SetPoint("TOPLEFT",10,-40-(i-1)*40) end
end

function WN:UpdateCollectionsSection(data)
    local page=self.sections.collections; if not page then return end
    page.headerTitle:SetText(self:T("COLLECTIONS_TITLE")); page.headerSub:SetText(self:T("COLLECTIONS_SUB"))
    local c=data.collections
    for kind,card in pairs(page.cards) do
        if kind=="achievements" then card.value:SetText(self:FormatNumber(c.achievementPoints)); card.meta:SetText(self:T("POINTS"))
        else local d=c[kind]; card.value:SetText(d.collected.." / "..d.total); card.meta:SetText(self:T("COLLECTED")) end
    end
    for kind,row in pairs(page.progress.rows) do local d=c[kind]; self:SetProgress(row.bar,d.collected,d.total,""); row.value:SetText(d.collected.." / "..d.total) end
end

function WN:CreateToolsSection(parent)
    local page=CreateFrame("Frame",nil,parent); page:SetAllPoints(); self.sections.tools=page; self:CreateSectionHeader(page)
    page.quick=self:CreatePanel(page,self:T("QUICK_ACCESS"),862,100); page.quick:SetPoint("TOPLEFT",0,-48)
    local defs={{"GROUP_FINDER","group",self.icons.group},{"CALENDAR","calendar",self.icons.calendar},{"MAP","map",self.icons.map},{"CHARACTER","character",self.icons.character},{"PROFESSIONS","professions",self.icons.profession},{"COLLECTIONS","collections",self.icons.collections},{"ADVENTURE_GUIDE","adventure",self.icons.info},{"TALENTS","talents",self.icons.talents}}
    for i,def in ipairs(defs) do
        local b=self:CreateIconButton(page.quick,96,54,def[3],self:T(def[1]),nil); b:SetPoint("TOPLEFT",10+(i-1)*105,-38); b.action=def[2]; b.textKey=def[1]
        b:RegisterForClicks("LeftButtonUp","RightButtonUp")
        b:SetScript("OnClick",function(btn,mouseButton) if mouseButton=="RightButton" then WN:ToggleFavorite(btn.action,WN:T(btn.textKey)) else WN:OpenTool(btn.action) end end)
    end
    page.performance=self:CreatePanel(page,self:T("PERFORMANCE"),280,320); page.performance:SetPoint("TOPLEFT",0,-160); page.performance.lines={}
    local keys={"FPS","FRAME_TIME","HOME_LATENCY","WORLD_LATENCY","ADDON_MEMORY","ADDON_CPU","GPU"}
    for i,key in ipairs(keys) do local row=MakeSmallLine(page.performance,-40-(i-1)*38,self.icons.info,self:T(key)); page.performance.lines[key]=row end
    page.addons=self:CreatePanel(page,self:T("ADDONS"),572,320); page.addons:SetPoint("TOPLEFT",page.performance,"TOPRIGHT",10,0)
    page.addons.summary=self:CreateText(page.addons,9,self.colors.muted,"LEFT"); page.addons.summary:SetPoint("TOPLEFT",10,-40); page.addons.summary:SetPoint("RIGHT",-10,0)
    page.addons.scroll,page.addons.scrollChild=self:CreateScrollArea(page.addons,8,-58,-28,8); page.addons.rows={}
    for i=1,30 do local row=self:CreateIconRow(page.addons.scrollChild,520,36); row:SetPoint("TOPLEFT",0,-(i-1)*39); row.icon:SetSize(24,24); page.addons.rows[i]=row end
    page.addons.scrollChild:SetSize(520,30*39)
end

function WN:UpdateToolsSection(data)
    local page=self.sections.tools; if not page then return end
    page.headerTitle:SetText(self:T("TOOLS_TITLE")); page.headerSub:SetText(self:T("TOOLS_SUB"))
    local p=self:UpdatePerformanceSnapshot(1)
    page.performance.lines.FPS.value:SetText(string.format("%.0f",p.fps or 0)); page.performance.lines.FRAME_TIME.value:SetText(string.format("%.1f ms",p.frameTime or 0)); page.performance.lines.HOME_LATENCY.value:SetText((p.home or 0).." ms"); page.performance.lines.WORLD_LATENCY.value:SetText((p.world or 0).." ms"); page.performance.lines.ADDON_MEMORY.value:SetText(self:FormatMemory(p.memory or 0)); page.performance.lines.ADDON_CPU.value:SetText(p.cpuPercent and string.format("%.1f%%",p.cpuPercent) or self:T("CPU_PROFILE_OFF")); page.performance.lines.GPU.value:SetText(self:T("GPU_UNAVAILABLE"))
    local report=self:GetAddonReport(); page.addons.summary:SetText(string.format("%s: %d   •   %s: %d   •   %s: %s",self:T("ADDONS"),report.total,self:T("LOADED"),report.loaded,self:T("MEMORY"),self:FormatMemory(report.memory)))
    local needed=math.max(1,#report.addons); page.addons.scrollChild:SetHeight(needed*39)
    for i = #page.addons.rows + 1, needed do
        local row=self:CreateIconRow(page.addons.scrollChild,520,36)
        row:SetPoint("TOPLEFT",0,-(i-1)*39)
        row.icon:SetSize(24,24)
        page.addons.rows[i]=row
    end
    for i,row in ipairs(page.addons.rows) do
        local addon=report.addons[i]
        if addon then
            row:Show(); row.icon:SetTexture(addon.loaded and self.icons.check or self.icons.info); row.name:SetText(addon.title)
            row.meta:SetText((addon.version~="" and ("v"..addon.version.." • ") or "")..(addon.loaded and self:T("LOADED") or addon.enabled and self:T("ENABLED") or self:T("DISABLED")))
            row.right:SetText(self:FormatMemory(addon.memory)); row.itemLink=nil
        else
            row:Hide()
        end
    end
end
