--------------------------------------------------------------------------------
-- Nanami-UI: Quest Log Skin (QuestLogSkin.lua)
-- Reskins the default QuestLogFrame with Nanami-UI styled interface
-- Maintains full compatibility with pfquest and other quest addons
--------------------------------------------------------------------------------

SFrames = SFrames or {}
SFrames.QuestLogSkin = {}
local QLS = SFrames.QuestLogSkin
SFramesDB = SFramesDB or {}

--------------------------------------------------------------------------------
-- Theme (Pink Cat-Paw)
--------------------------------------------------------------------------------
local T = SFrames.Theme:Extend({
    objectiveComplete = { 0.45, 0.90, 0.45 },
    objectiveIncomplete = { 0.85, 0.78, 0.70 },
    tagElite    = { 1.0, 0.65, 0.20 },
    tagDungeon  = { 0.40, 0.70, 1.0 },
    tagRaid     = { 0.70, 0.45, 1.0 },
    tagPvP      = { 0.90, 0.30, 0.30 },
    tagComplete = { 0.40, 0.90, 0.40 },
})

--------------------------------------------------------------------------------
-- Layout
--------------------------------------------------------------------------------
local FRAME_W      = 595
local LIST_W       = 250
local DETAIL_PAD   = 8
local HEADER_H     = 30
local BOTTOM_H     = 36
local INNER_PAD    = 6
local SCROLL_W     = 14
local LIST_BTN_W   = LIST_W - INNER_PAD * 2 - SCROLL_W - 4

--------------------------------------------------------------------------------
-- State
--------------------------------------------------------------------------------
local skinApplied = false

--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local function GetFont()
    if SFrames and SFrames.GetFont then return SFrames:GetFont() end
    return "Fonts\\ARIALN.TTF"
end

local function SetRoundBackdrop(frame, bgColor, borderColor)
    frame:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 14,
        insets = { left = 3, right = 3, top = 3, bottom = 3 },
    })
    local bg = bgColor or T.panelBg
    local bd = borderColor or T.panelBorder
    frame:SetBackdropColor(bg[1], bg[2], bg[3], bg[4] or 1)
    frame:SetBackdropBorderColor(bd[1], bd[2], bd[3], bd[4] or 1)
end

local function CreateShadow(parent)
    local s = CreateFrame("Frame", nil, parent)
    s:SetPoint("TOPLEFT", parent, "TOPLEFT", -4, 4)
    s:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", 4, -4)
    s:SetFrameLevel(math.max(parent:GetFrameLevel() - 1, 0))
    s:SetBackdrop({
        bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = { left = 4, right = 4, top = 4, bottom = 4 },
    })
    s:SetBackdropColor(0, 0, 0, 0.6)
    s:SetBackdropBorderColor(0, 0, 0, 0.45)
    return s
end

local function StripTextures(frame)
    if not frame then return end
    local regions = { frame:GetRegions() }
    for i = 1, table.getn(regions) do
        local region = regions[i]
        if region and region.SetTexture and not region._nanamiKeep then
            local drawLayer = region.GetDrawLayer and region:GetDrawLayer()
            if drawLayer == "BACKGROUND" or drawLayer == "BORDER" or drawLayer == "ARTWORK" then
                region:SetTexture(nil)
                region:SetAlpha(0)
                region:Hide()
            end
        end
    end
end

local function StripAllTextures(frame)
    if not frame then return end
    local regions = { frame:GetRegions() }
    for i = 1, table.getn(regions) do
        local region = regions[i]
        if region and region.SetTexture and not region._nanamiKeep then
            region:SetTexture(nil)
            region:SetAlpha(0)
            region:Hide()
        end
    end
end

local function StripNormalTexture(btn)
    if not btn or not btn.GetNormalTexture then return end
    local nt = btn:GetNormalTexture()
    if nt then nt:SetTexture(nil); nt:SetAlpha(0) end
end

local function StripPushedTexture(btn)
    if not btn or not btn.GetPushedTexture then return end
    local pt = btn:GetPushedTexture()
    if pt then pt:SetTexture(nil); pt:SetAlpha(0) end
end

local function StripHighlightTexture(btn)
    if not btn or not btn.GetHighlightTexture then return end
    local ht = btn:GetHighlightTexture()
    if ht then ht:SetTexture(nil); ht:SetAlpha(0) end
end

local function StripDisabledTexture(btn)
    if not btn or not btn.GetDisabledTexture then return end
    local dt = btn:GetDisabledTexture()
    if dt then dt:SetTexture(nil); dt:SetAlpha(0) end
end

local QUALITY_COLORS = {
    [0] = { 0.62, 0.62, 0.62 }, [1] = { 1, 1, 1 },
    [2] = { 0.12, 1, 0 },       [3] = { 0.0, 0.44, 0.87 },
    [4] = { 0.64, 0.21, 0.93 }, [5] = { 1, 0.5, 0 },
}

local LINK_QUALITY_MAP = {
    ["9d9d9d"] = 0, ["ffffff"] = 1, ["1eff00"] = 2,
    ["0070dd"] = 3, ["a335ee"] = 4, ["ff8000"] = 5,
    ["e6cc80"] = 6,
}

local function QualityFromLink(link)
    if not link then return nil end
    local _, _, hex = string.find(link, "|c(%x%x%x%x%x%x%x%x)|")
    if hex and string.len(hex) == 8 then
        local color = string.lower(string.sub(hex, 3, 8))
        return LINK_QUALITY_MAP[color]
    end
    return nil
end

local function GetQuestGreenRange()
    local level = UnitLevel("player") or 60
    if level <= 5 then return 0 end
    if level <= 39 then return math.floor(level / 10) + 5 end
    return math.floor(level / 5) + 1 + 8
end

local function GetDiffColor(level)
    local pLvl = UnitLevel("player") or 60
    local diff = (level or pLvl) - pLvl
    if diff >= 5 then return 1, 0.10, 0.10
    elseif diff >= 3 then return 1, 0.50, 0.25
    elseif diff >= -2 then return 1, 1, 0
    elseif diff >= -GetQuestGreenRange() then return 0.25, 0.75, 0.25
    else return 0.50, 0.50, 0.50
    end
end

--------------------------------------------------------------------------------
-- Scrollbar Skinning
--------------------------------------------------------------------------------
local function SkinScrollBar(scrollBarName)
    local sb = _G[scrollBarName]
    if not sb then return end
    StripAllTextures(sb)

    local track = sb:CreateTexture(nil, "BACKGROUND")
    track:SetTexture("Interface\\Buttons\\WHITE8X8")
    track:SetVertexColor(T.scrollTrack[1], T.scrollTrack[2], T.scrollTrack[3], T.scrollTrack[4])
    track:SetWidth(6)
    track:SetPoint("TOP", sb, "TOP", 0, -16)
    track:SetPoint("BOTTOM", sb, "BOTTOM", 0, 16)

    local thumb = sb:GetThumbTexture()
    if thumb then
        thumb:SetTexture("Interface\\Buttons\\WHITE8X8")
        thumb:SetVertexColor(T.scrollThumb[1], T.scrollThumb[2], T.scrollThumb[3], T.scrollThumb[4])
        thumb:SetWidth(6)
        thumb:SetHeight(40)
    end

    for _, suffix in ipairs({"ScrollUpButton", "ScrollDownButton"}) do
        local b = _G[scrollBarName .. suffix]
        if b then
            StripAllTextures(b)
            StripNormalTexture(b)
            StripPushedTexture(b)
            StripDisabledTexture(b)
            StripHighlightTexture(b)
            b:SetWidth(6)
            b:SetHeight(6)
        end
    end
end

--------------------------------------------------------------------------------
-- Action Button Skinning
--------------------------------------------------------------------------------
local btnDisabledBg = { 0.08, 0.04, 0.06, 0.60 }
local btnDisabledBd = { 0.22, 0.14, 0.18, 0.40 }
local btnDisabledText = { 0.35, 0.25, 0.30 }

local function RefreshButtonDisabledLook(btn)
    if not btn then return end
    local disabled = false
    if btn.IsEnabled then
        local ok, result = pcall(btn.IsEnabled, btn)
        if ok then disabled = not result end
    end
    if disabled then
        SetRoundBackdrop(btn, btnDisabledBg, btnDisabledBd)
        if btn.GetFontString then
            local fs = btn:GetFontString()
            if fs then fs:SetTextColor(btnDisabledText[1], btnDisabledText[2], btnDisabledText[3]) end
        end
    else
        SetRoundBackdrop(btn, T.btnBg, T.btnBorder)
        if btn.GetFontString then
            local fs = btn:GetFontString()
            if fs then fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) end
        end
    end
end

local function SkinActionButton(btn)
    if not btn or btn._nanamiActionSkinned then return end
    btn._nanamiActionSkinned = true
    StripAllTextures(btn)
    StripNormalTexture(btn)
    StripPushedTexture(btn)
    StripHighlightTexture(btn)
    SetRoundBackdrop(btn, T.btnBg, T.btnBorder)

    if btn.GetFontString then
        local fs = btn:GetFontString()
        if fs then
            fs:SetFont(GetFont(), 11, "OUTLINE")
            fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
        end
    end

    local origEnter = btn:GetScript("OnEnter")
    btn:SetScript("OnEnter", function()
        local disabled = false
        if this.IsEnabled then
            local ok, r = pcall(this.IsEnabled, this)
            if ok then disabled = not r end
        end
        if disabled then
            if origEnter then origEnter() end
            return
        end
        SetRoundBackdrop(this, T.btnHoverBg, T.btnHoverBd)
        if this.GetFontString then
            local tfs = this:GetFontString()
            if tfs then tfs:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end
        end
        if origEnter then origEnter() end
    end)
    local origLeave = btn:GetScript("OnLeave")
    btn:SetScript("OnLeave", function()
        local disabled = false
        if this.IsEnabled then
            local ok, r = pcall(this.IsEnabled, this)
            if ok then disabled = not r end
        end
        if disabled then
            RefreshButtonDisabledLook(this)
            if origLeave then origLeave() end
            return
        end
        SetRoundBackdrop(this, T.btnBg, T.btnBorder)
        if this.GetFontString then
            local tfs = this:GetFontString()
            if tfs then tfs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) end
        end
        if origLeave then origLeave() end
    end)
    btn:SetScript("OnMouseDown", function()
        local disabled = false
        if this.IsEnabled then
            local ok, r = pcall(this.IsEnabled, this)
            if ok then disabled = not r end
        end
        if disabled then return end
        SetRoundBackdrop(this, T.btnDownBg, T.btnBorder)
    end)
    btn:SetScript("OnMouseUp", function()
        local disabled = false
        if this.IsEnabled then
            local ok, r = pcall(this.IsEnabled, this)
            if ok then disabled = not r end
        end
        if disabled then return end
        SetRoundBackdrop(this, T.btnHoverBg, T.btnHoverBd)
    end)
end

--------------------------------------------------------------------------------
-- Reward Item Skinning
--------------------------------------------------------------------------------
local function SkinRewardItem(btn)
    if not btn or btn._nanamiSkinned then return end
    btn._nanamiSkinned = true

    local bname = btn:GetName() or ""

    local iconTex = _G[bname .. "IconTexture"]
    if iconTex then iconTex._nanamiKeep = true end

    StripAllTextures(btn)
    StripNormalTexture(btn)
    SetRoundBackdrop(btn, T.rewardBg, T.rewardBorder)

    if iconTex then
        iconTex:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        iconTex:ClearAllPoints()
        iconTex:SetPoint("LEFT", btn, "LEFT", 4, 0)
        iconTex:SetWidth(30); iconTex:SetHeight(30)
        iconTex:SetAlpha(1)
        iconTex:Show()
    end
    local nameFrame = _G[bname .. "NameFrame"]
    if nameFrame then nameFrame:SetTexture(nil); nameFrame:SetAlpha(0) end
    local nameText = _G[bname .. "Name"]
    if nameText then
        nameText:SetFont(GetFont(), 11, "OUTLINE")
        nameText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
    end
    local countText = _G[bname .. "Count"]
    if countText then countText:SetFont(GetFont(), 10, "OUTLINE") end
end

--------------------------------------------------------------------------------
-- Quest Log Item Quality Coloring
--------------------------------------------------------------------------------
local function GetQuestLogItemQuality(itemType, index)
    if itemType == "choice" and GetQuestLogChoiceInfo then
        local ok, name, tex, num, q, usable = pcall(GetQuestLogChoiceInfo, index)
        if ok and q and q > 0 then return q end
    elseif itemType == "reward" and GetQuestLogRewardInfo then
        local ok, name, tex, num, q, usable = pcall(GetQuestLogRewardInfo, index)
        if ok and q and q > 0 then return q end
    end
    if GetQuestLogItemLink then
        local ok, link = pcall(GetQuestLogItemLink, itemType, index)
        if ok and link then
            local q = QualityFromLink(link)
            if q then return q end
            if GetItemInfo then
                local ok2, _, _, iq = pcall(GetItemInfo, link)
                if ok2 and iq and iq > 0 then return iq end
            end
        end
    end
    return nil
end

local function ApplyQuestLogItemQuality()
    local choiceIdx = 0
    local rewardIdx = 0
    for i = 1, 10 do
        local item = _G["QuestLogItem" .. i]
        if not item or not item:IsVisible() then break end

        local bname = item:GetName() or ""
        local nameText = _G[bname .. "Name"]
        if not nameText then break end

        local itemType = item.type
        local idx = 0
        if itemType == "choice" then
            choiceIdx = choiceIdx + 1
            idx = choiceIdx
        elseif itemType == "reward" then
            rewardIdx = rewardIdx + 1
            idx = rewardIdx
        else
            break
        end

        local quality = GetQuestLogItemQuality(itemType, idx)
        local qc = quality and QUALITY_COLORS[quality]
        if qc and quality >= 2 then
            nameText:SetTextColor(qc[1], qc[2], qc[3])
            item:SetBackdropBorderColor(qc[1], qc[2], qc[3], 0.8)
        elseif qc and quality == 1 then
            nameText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
            item:SetBackdropBorderColor(T.rewardBorder[1], T.rewardBorder[2], T.rewardBorder[3], T.rewardBorder[4])
        else
            nameText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
            item:SetBackdropBorderColor(T.rewardBorder[1], T.rewardBorder[2], T.rewardBorder[3], T.rewardBorder[4])
        end
    end
end

--------------------------------------------------------------------------------
-- Tag Color for elite/dungeon/raid/pvp/complete
--------------------------------------------------------------------------------
local function GetTagColor(tagText)
    if not tagText or tagText == "" then return nil end
    local t = string.lower(tagText)
    if string.find(t, "elite") or string.find(t, "精英") then
        return T.tagElite
    elseif string.find(t, "dungeon") or string.find(t, "地下城") then
        return T.tagDungeon
    elseif string.find(t, "raid") or string.find(t, "团队") then
        return T.tagRaid
    elseif string.find(t, "pvp") then
        return T.tagPvP
    elseif string.find(t, "complete") or string.find(t, "完成") then
        return T.tagComplete
    end
    return T.dimText
end

--------------------------------------------------------------------------------
-- Main Frame Skinning
--------------------------------------------------------------------------------
local function SkinMainFrame()
    local f = QuestLogFrame
    if not f then return end

    -- Resize frame to remove excess right-side space
    f:SetWidth(FRAME_W)

    StripTextures(f)
    SetRoundBackdrop(f, T.panelBg, T.panelBorder)
    CreateShadow(f)

    for _, pName in ipairs({"QuestLogFramePortrait", "QuestLogPortrait"}) do
        local p = _G[pName]
        if p then p:SetTexture(nil); p:SetAlpha(0); p:Hide() end
    end

    local titleText = QuestLogTitleText
    if titleText then
        titleText:SetFont(GetFont(), 14, "OUTLINE")
        titleText:SetTextColor(T.gold[1], T.gold[2], T.gold[3])
        titleText:ClearAllPoints()
        titleText:SetPoint("LEFT", f, "TOPLEFT", 14, -15)
    end

    -- Quest count to top-right
    local questCount = QuestLogQuestCount
    if questCount then
        questCount:SetFont(GetFont(), 11, "OUTLINE")
        questCount:SetTextColor(T.countText[1], T.countText[2], T.countText[3])
        questCount:ClearAllPoints()
        questCount:SetPoint("RIGHT", f, "TOPRIGHT", -30, -15)
    end

    local closeBtn = _G["QuestLogFrameCloseButton"]
    if closeBtn then
        closeBtn:ClearAllPoints()
        closeBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -2, -2)
        closeBtn:SetWidth(22); closeBtn:SetHeight(22)
        closeBtn:SetFrameLevel(f:GetFrameLevel() + 10)
    end

    -- Make frame draggable and respond to ESC
    if UIPanelWindows then
        UIPanelWindows["QuestLogFrame"] = nil
    end
    table.insert(UISpecialFrames, "QuestLogFrame")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:SetClampedToScreen(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", function() this:StartMoving() end)
    f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)

    -- Header separator
    local sep = f:CreateTexture(nil, "ARTWORK")
    sep:SetTexture("Interface\\Buttons\\WHITE8X8")
    sep:SetHeight(1)
    sep:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -HEADER_H)
    sep:SetPoint("TOPRIGHT", f, "TOPRIGHT", -8, -HEADER_H)
    sep:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4])

    -- Bottom separator
    local bsep = f:CreateTexture(nil, "ARTWORK")
    bsep:SetTexture("Interface\\Buttons\\WHITE8X8")
    bsep:SetHeight(1)
    bsep:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 8, BOTTOM_H)
    bsep:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -8, BOTTOM_H)
    bsep:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4])

    -- Detect and preserve Turtle WoW translate / ? buttons
    -- Also find any unrecognized buttons and ensure they remain visible
    local knownPrefixes = {
        "QuestLogTitle", "QuestLogFrame", "QuestLogCollapseAll",
        "QuestLogTrack", "QuestFramePush", "pfQuest",
    }
    local function isKnownButton(child)
        if child._nanamiPfSkinned or child._nanamiBottomBtn
            or child._nanamiActionSkinned then return true end
        local cname = child:GetName() or ""
        if cname == "" then return false end
        for ki = 1, table.getn(knownPrefixes) do
            if string.find(cname, knownPrefixes[ki]) then return true end
        end
        return false
    end

    f._skinExtraButtons = function()
        local searchParents = {}
        table.insert(searchParents, f)
        local dc = _G["QuestLogDetailScrollFrameChildFrame"]
            or _G["QuestLogDetailScrollFrameChild"]
        if dc then table.insert(searchParents, dc) end
        local ds = QuestLogDetailScrollFrame
        if ds then table.insert(searchParents, ds) end

        local detailLevel = (f._nanamiDetailPanel and f._nanamiDetailPanel:GetFrameLevel()) or (f:GetFrameLevel() + 2)

        for pi = 1, table.getn(searchParents) do
            local parent = searchParents[pi]
            if parent and parent.GetChildren then
                local children = { parent:GetChildren() }
                for ci = 1, table.getn(children) do
                    local child = children[ci]
                    if child and child.GetObjectType then
                        local objType = child:GetObjectType()
                        if objType == "Button" and not isKnownButton(child) then
                            -- Ensure button is visible above detailPanel
                            if child:GetFrameLevel() <= detailLevel then
                                child:SetFrameLevel(detailLevel + 3)
                            end
                            child:Show()
                            SkinPfQuestButton(child)
                        end
                    end
                end
            end
        end

        -- Also search for globally named Turtle WoW translate buttons
        for _, gname in ipairs({
            "QuestTranslateButton", "QuestLogTranslateButton",
            "QuestInfoTranslateButton", "TurtleTranslateButton",
            "QuestTranslationButton", "QuestHelpButton",
        }) do
            local gb = _G[gname]
            if gb and gb.GetObjectType and not gb._nanamiPfSkinned then
                gb:Show()
                if gb:GetFrameLevel() <= detailLevel then
                    gb:SetFrameLevel(detailLevel + 3)
                end
                SkinPfQuestButton(gb)
            end
        end
    end
end

--------------------------------------------------------------------------------
-- Quest List Panel Skinning
--------------------------------------------------------------------------------
local function SkinQuestList()
    local listFrame = QuestLogListScrollFrame
    if not listFrame then return end
    local f = QuestLogFrame

    local listPanel = CreateFrame("Frame", nil, f)
    listPanel:SetPoint("TOPLEFT", f, "TOPLEFT", DETAIL_PAD, -(HEADER_H + 2))
    listPanel:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", DETAIL_PAD, BOTTOM_H + 2)
    listPanel:SetWidth(LIST_W)
    SetRoundBackdrop(listPanel, T.listBg, T.listBorder)
    listPanel:SetFrameLevel(f:GetFrameLevel() + 1)
    f._nanamiListPanel = listPanel

    listFrame:ClearAllPoints()
    listFrame:SetPoint("TOPLEFT", listPanel, "TOPLEFT", INNER_PAD, -INNER_PAD)
    listFrame:SetPoint("BOTTOMRIGHT", listPanel, "BOTTOMRIGHT", -(SCROLL_W + INNER_PAD), 4)
    listFrame:SetWidth(LIST_W - INNER_PAD * 2 - SCROLL_W)

    StripTextures(listFrame)
    SkinScrollBar("QuestLogListScrollFrameScrollBar")

    local collapseAll = QuestLogCollapseAllButton
    if collapseAll then
        StripNormalTexture(collapseAll)
        StripPushedTexture(collapseAll)
        StripHighlightTexture(collapseAll)
    end

    local highlight = _G["QuestLogHighlightFrame"]
    if highlight then
        StripAllTextures(highlight)
        highlight:SetBackdrop({
            bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
            tile = true, tileSize = 16,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        highlight:SetBackdropColor(T.questSelected[1], T.questSelected[2], T.questSelected[3], T.questSelected[4])

        local hlBar = highlight:CreateTexture(nil, "OVERLAY")
        hlBar:SetTexture("Interface\\Buttons\\WHITE8X8")
        hlBar:SetWidth(3)
        hlBar:SetPoint("TOPLEFT", highlight, "TOPLEFT", 0, 0)
        hlBar:SetPoint("BOTTOMLEFT", highlight, "BOTTOMLEFT", 0, 0)
        hlBar:SetVertexColor(T.questSelBar[1], T.questSelBar[2], T.questSelBar[3], T.questSelBar[4])
    end
end

--------------------------------------------------------------------------------
-- Quest Detail Panel Skinning
--------------------------------------------------------------------------------
local function SkinQuestDetail()
    local detailFrame = QuestLogDetailScrollFrame
    if not detailFrame then return end
    local f = QuestLogFrame

    local DETAIL_W = FRAME_W - LIST_W - DETAIL_PAD * 2 - 4

    local detailPanel = CreateFrame("Frame", nil, f)
    detailPanel:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + DETAIL_PAD + 4, -(HEADER_H + 2))
    detailPanel:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -DETAIL_PAD, BOTTOM_H + 2)
    SetRoundBackdrop(detailPanel, T.detailBg, T.detailBorder)
    detailPanel:SetFrameLevel(f:GetFrameLevel() + 1)
    f._nanamiDetailPanel = detailPanel

    detailFrame:ClearAllPoints()
    detailFrame:SetPoint("TOPLEFT", detailPanel, "TOPLEFT", INNER_PAD, -INNER_PAD)
    detailFrame:SetPoint("BOTTOMRIGHT", detailPanel, "BOTTOMRIGHT", -(SCROLL_W + INNER_PAD), INNER_PAD)
    detailFrame:SetFrameLevel(detailPanel:GetFrameLevel() + 2)

    StripTextures(detailFrame)
    SkinScrollBar("QuestLogDetailScrollFrameScrollBar")

    local contentW = DETAIL_W - INNER_PAD * 2 - SCROLL_W - 6
    local detailChild = _G["QuestLogDetailScrollFrameChildFrame"]
        or _G["QuestLogDetailScrollFrameChild"]
    if detailChild and contentW > 100 then
        detailChild:SetWidth(contentW)
    end

    if QuestLogNoQuestsText then
        QuestLogNoQuestsText:SetFont(GetFont(), 13)
        QuestLogNoQuestsText:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
    end
    if EmptyQuestLogFrame then
        StripTextures(EmptyQuestLogFrame)
        local et = _G["EmptyQuestLogFrameText"]
        if et then
            et:SetFont(GetFont(), 13)
            et:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
        end
    end
end

--------------------------------------------------------------------------------
-- Bottom Buttons Skinning
--------------------------------------------------------------------------------
local function SkinBottomButtons()
    local f = QuestLogFrame
    local btnW = math.floor((FRAME_W - 40) / 3)
    if btnW > 120 then btnW = 120 end
    if btnW < 80 then btnW = 80 end

    local abandonBtn = QuestLogFrameAbandonButton
    if abandonBtn then
        SkinActionButton(abandonBtn)
        abandonBtn:SetHeight(24)
        abandonBtn:ClearAllPoints()
        abandonBtn:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 12, 6)
        abandonBtn:SetWidth(btnW)
        abandonBtn._nanamiBottomBtn = true
    end

    local shareBtn = _G["QuestLogFramePushQuestButton"] or _G["QuestFramePushQuestButton"]
    if shareBtn then
        SkinActionButton(shareBtn)
        shareBtn:SetHeight(24)
        shareBtn:ClearAllPoints()
        shareBtn:SetPoint("BOTTOM", f, "BOTTOM", 0, 6)
        shareBtn:SetWidth(btnW)
        shareBtn._nanamiBottomBtn = true
        shareBtn._nanamiOrigText = nil
        if shareBtn.GetFontString then
            local fs = shareBtn:GetFontString()
            if fs then shareBtn._nanamiOrigText = fs:GetText() end
        end

        shareBtn._nanamiRefreshShare = function(sb)
            if not sb then return end
            local canShare = GetQuestLogPushable and GetQuestLogPushable()
            local fs = sb.GetFontString and sb:GetFontString()
            if not canShare then
                SetRoundBackdrop(sb, btnDisabledBg, btnDisabledBd)
                if fs then
                    fs:SetTextColor(btnDisabledText[1], btnDisabledText[2], btnDisabledText[3])
                end
            else
                SetRoundBackdrop(sb, T.btnBg, T.btnBorder)
                if fs then
                    fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
                end
            end
        end

        shareBtn._nanamiRefreshShare(shareBtn)

        local sharePoll = CreateFrame("Frame", nil, shareBtn)
        sharePoll._t = 0
        sharePoll:SetScript("OnUpdate", function()
            this._t = (this._t or 0) + (arg1 or 0)
            if this._t < 1.0 then return end
            this._t = 0
            local sb = this:GetParent()
            if sb and sb._nanamiRefreshShare then sb._nanamiRefreshShare(sb) end
        end)
    end

    -- Search for exit button by multiple names and text content
    local exitBtn = nil
    for _, eName in ipairs({
        "QuestLogFrameExitButton", "QuestLogExitButton",
        "QuestLogCancelButton", "QuestLogCloseButton",
        "QuestLogFrameCancelButton",
    }) do
        if _G[eName] then exitBtn = _G[eName]; break end
    end

    -- Fallback: find any bottom button with "退出"/"Exit"/"Close" text
    if not exitBtn then
        local children = { f:GetChildren() }
        for ci = 1, table.getn(children) do
            local child = children[ci]
            if child and child.GetObjectType and child:GetObjectType() == "Button"
                and child.GetFontString then
                local cfs = child:GetFontString()
                if cfs then
                    local txt = cfs:GetText()
                    if txt and (string.find(txt, "退出") or string.find(txt, "Exit")
                        or string.find(txt, "Close") or string.find(txt, "关闭")) then
                        exitBtn = child
                        break
                    end
                end
            end
        end
    end

    if exitBtn then
        SkinActionButton(exitBtn)
        exitBtn:SetHeight(24)
        exitBtn:ClearAllPoints()
        exitBtn:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -12, 6)
        exitBtn:SetWidth(btnW)
        exitBtn._nanamiBottomBtn = true
    end

    -- Also skin any other unskinned bottom-area buttons (Turtle WoW additions)
    local children = { f:GetChildren() }
    for ci = 1, table.getn(children) do
        local child = children[ci]
        if child and child.GetObjectType and child:GetObjectType() == "Button"
            and not child._nanamiBottomBtn and not child._nanamiPfSkinned
            and not child._nanamiActionSkinned then
            -- Check if this button is near the bottom of the frame
            local point = child.GetPoint and child:GetPoint()
            if point and (point == "BOTTOMLEFT" or point == "BOTTOMRIGHT" or point == "BOTTOM") then
                if child.GetFontString then
                    local cfs = child:GetFontString()
                    if cfs then
                        local txt = cfs:GetText()
                        if txt and txt ~= "" then
                            SkinActionButton(child)
                            child._nanamiBottomBtn = true
                        end
                    end
                end
            end
        end
    end
end

--------------------------------------------------------------------------------
-- Quest List Entries Restyling
--------------------------------------------------------------------------------
local function GetHighlightAnchorBtn()
    local hl = _G["QuestLogHighlightFrame"]
    if hl and hl.IsVisible and hl:IsVisible() and hl.GetPoint then
        local ok, _, anchor = pcall(hl.GetPoint, hl)
        if ok and anchor then return anchor end
    end
    return nil
end

local function StyleQuestListEntries()
    local numEntries, numQuests = 0, 0
    if GetNumQuestLogEntries then
        numEntries, numQuests = GetNumQuestLogEntries()
    end
    local questsDisplayed = QUESTS_DISPLAYED or 22
    local hlBtn = GetHighlightAnchorBtn()

    for i = 1, questsDisplayed do
        local btn = _G["QuestLogTitle" .. i]
        if not btn then break end

        if not btn._nanamiSkinned then
            StripPushedTexture(btn)

            local nt = _G["QuestLogTitle" .. i .. "NormalText"]
            if nt then nt:SetFont(GetFont(), 11) end
            local tg = _G["QuestLogTitle" .. i .. "Tag"]
            if tg then tg:SetFont(GetFont(), 10, "OUTLINE") end

            local origHL = btn:GetHighlightTexture()
            if origHL then
                origHL:SetTexture("Interface\\Buttons\\WHITE8X8")
                origHL:SetVertexColor(T.questHover[1], T.questHover[2], T.questHover[3], T.questHover[4])
                origHL:SetAllPoints(btn)
                origHL:SetBlendMode("ADD")
            end

            btn._nanamiCollapse = btn:CreateFontString(nil, "OVERLAY")
            btn._nanamiCollapse:SetFont(GetFont(), 12, "OUTLINE")
            btn._nanamiCollapse:SetPoint("LEFT", btn, "LEFT", 2, 0)
            btn._nanamiCollapse:SetTextColor(T.collapseIcon[1], T.collapseIcon[2], T.collapseIcon[3])
            btn._nanamiCollapse:Hide()

            btn._nanamiTrackBar = btn:CreateTexture(nil, "OVERLAY")
            btn._nanamiTrackBar:SetTexture("Interface\\Buttons\\WHITE8X8")
            btn._nanamiTrackBar:SetWidth(3)
            btn._nanamiTrackBar:SetPoint("TOPRIGHT", btn, "TOPRIGHT", 0, 0)
            btn._nanamiTrackBar:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", 0, 0)
            btn._nanamiTrackBar:SetVertexColor(T.trackBar[1], T.trackBar[2], T.trackBar[3], 1)
            btn._nanamiTrackBar:Hide()

            btn._nanamiTrackLabel = btn:CreateFontString(nil, "OVERLAY")
            btn._nanamiTrackLabel:SetFont(GetFont(), 9, "OUTLINE")
            btn._nanamiTrackLabel:SetPoint("RIGHT", btn, "RIGHT", -6, 0)
            btn._nanamiTrackLabel:SetTextColor(T.trackBar[1], T.trackBar[2], T.trackBar[3], 1)
            btn._nanamiTrackLabel:Hide()

            local gmFS = _G["QuestLogTitle" .. i .. "GroupMates"]
            if gmFS and gmFS.SetFont then
                gmFS:SetFont(GetFont(), 10, "OUTLINE")
            end

            btn._nanamiSkinned = true
        end

        btn:SetWidth(LIST_BTN_W)

        local normalText = _G["QuestLogTitle" .. i .. "NormalText"]
        local tagFS = _G["QuestLogTitle" .. i .. "Tag"]

        if btn:IsVisible() and normalText then
            normalText:SetWidth(LIST_BTN_W - 30)

            local questIndex = btn.questLogIndex
            local isSelected = (btn == hlBtn) and not btn.isHeader

            if btn.isHeader then
                normalText:SetTextColor(T.zoneHeader[1], T.zoneHeader[2], T.zoneHeader[3])
                if btn._nanamiCollapse then
                    local collapsed = false
                    if btn.IsExpanded then
                        collapsed = not btn:IsExpanded()
                    elseif btn.IsCollapsed then
                        collapsed = btn:IsCollapsed()
                    end
                    local ntex = btn.GetNormalTexture and btn:GetNormalTexture()
                    if ntex then
                        local tex = ntex.GetTexture and ntex:GetTexture()
                        if tex then
                            tex = string.lower(tex)
                            if string.find(tex, "plus") or string.find(tex, "expand") then
                                collapsed = true
                            elseif string.find(tex, "minus") or string.find(tex, "collapse") then
                                collapsed = false
                            end
                        end
                        ntex:SetAlpha(0)
                    end
                    btn._nanamiCollapse:SetText(collapsed and "+" or "-")
                    btn._nanamiCollapse:Show()
                end
                if btn._nanamiTrackBar then btn._nanamiTrackBar:Hide() end
                if btn._nanamiTrackLabel then btn._nanamiTrackLabel:Hide() end
                if tagFS then tagFS:SetText("") end
            else
                local diffR, diffG, diffB
                if questIndex and GetQuestLogTitle then
                    local _, level = GetQuestLogTitle(questIndex)
                    if level and level > 0 then
                        if GetQuestDifficultyColor then
                            local c = GetQuestDifficultyColor(level)
                            if c then diffR, diffG, diffB = c.r, c.g, c.b end
                        end
                        if not diffR then
                            diffR, diffG, diffB = GetDiffColor(level)
                        end
                    end
                end
                if diffR then
                    normalText:SetTextColor(diffR, diffG, diffB)
                elseif btn.GetTextColor then
                    local cr, cg, cb = btn:GetTextColor()
                    if cr then normalText:SetTextColor(cr, cg, cb) end
                end

                if isSelected then
                    normalText:SetTextColor(1, 1, 1)
                end

                if btn._nanamiCollapse then btn._nanamiCollapse:Hide() end

                local check = _G["QuestLogTitle" .. i .. "Check"]
                local isTracked = check and check.IsVisible and check:IsVisible()
                if btn._nanamiTrackBar then
                    if isTracked then btn._nanamiTrackBar:Show() else btn._nanamiTrackBar:Hide() end
                end
                if btn._nanamiTrackLabel then btn._nanamiTrackLabel:Hide() end
                if check then
                    if isTracked then
                        check:SetVertexColor(T.trackBar[1], T.trackBar[2], T.trackBar[3], 1)
                        check:SetWidth(14)
                        check:SetHeight(14)
                    else
                        check:SetWidth(12)
                        check:SetHeight(12)
                    end
                end

                if tagFS then
                    local tagText = tagFS:GetText()
                    if tagText and tagText ~= "" then
                        if isSelected then
                            tagFS:SetTextColor(1, 1, 1)
                        elseif diffR then
                            tagFS:SetTextColor(diffR, diffG, diffB)
                        elseif btn.GetTextColor then
                            local cr, cg, cb = btn:GetTextColor()
                            if cr then tagFS:SetTextColor(cr, cg, cb) end
                        end
                    end
                end
            end

            -- check icon is handled in the tracking section above
        end
    end
end

--------------------------------------------------------------------------------
-- Quest Detail Text Restyling
--------------------------------------------------------------------------------
local function StyleQuestDetailText()
    local titleFS = _G["QuestLogQuestTitle"]
    if titleFS then
        titleFS:SetFont(GetFont(), 14, "OUTLINE")
        titleFS:SetTextColor(T.gold[1], T.gold[2], T.gold[3])
    end

    local descFS = _G["QuestLogQuestDescription"]
    if descFS then
        descFS:SetFont(GetFont(), 12)
        descFS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
    end

    local objectivesTitle = _G["QuestLogObjectivesText"]
    if objectivesTitle then
        objectivesTitle:SetFont(GetFont(), 12)
        objectivesTitle:SetTextColor(T.sectionTitle[1], T.sectionTitle[2], T.sectionTitle[3])
    end

    local descTitle = _G["QuestLogDescriptionTitle"]
    if descTitle then
        descTitle:SetFont(GetFont(), 12, "OUTLINE")
        descTitle:SetTextColor(T.sectionTitle[1], T.sectionTitle[2], T.sectionTitle[3])
    end

    for i = 1, 20 do
        local objFS = _G["QuestLogObjective" .. i]
        if not objFS then break end
        objFS:SetFont(GetFont(), 11)
        local text = objFS:GetText()
        if text then
            local _, _, done, needed = string.find(text, "(%d+)/(%d+)")
            if done and needed and tonumber(done) >= tonumber(needed) then
                objFS:SetTextColor(T.objectiveComplete[1], T.objectiveComplete[2], T.objectiveComplete[3])
            else
                objFS:SetTextColor(T.objectiveIncomplete[1], T.objectiveIncomplete[2], T.objectiveIncomplete[3])
            end
        end
    end

    local styledTexts = {
        "QuestLogRewardTitleText", "QuestLogHeaderText",
        "QuestLogItemChooseText", "QuestLogItemReceiveText",
        "QuestLogSpellLearnText",
    }
    for _, name in ipairs(styledTexts) do
        local fs = _G[name]
        if fs then
            fs:SetFont(GetFont(), 11, "OUTLINE")
            fs:SetTextColor(T.sectionTitle[1], T.sectionTitle[2], T.sectionTitle[3])
        end
    end

    local rewardMoney = _G["QuestLogRequiredMoneyText"]
    if rewardMoney then rewardMoney:SetFont(GetFont(), 11) end

    local timerText = _G["QuestLogTimerText"]
    if timerText then
        timerText:SetFont(GetFont(), 11, "OUTLINE")
        timerText:SetTextColor(T.gold[1], T.gold[2], T.gold[3])
    end

    for i = 1, 10 do
        local item = _G["QuestLogItem" .. i]
        if item then SkinRewardItem(item) end
    end

    ApplyQuestLogItemQuality()
end

--------------------------------------------------------------------------------
-- pfquest Button Detection & Styling
--------------------------------------------------------------------------------
local pfquestSkinned = false

local function SkinPfQuestButton(btn)
    if not btn or btn._nanamiPfSkinned then return end
    btn._nanamiPfSkinned = true
    StripAllTextures(btn)
    StripNormalTexture(btn)
    StripPushedTexture(btn)
    StripHighlightTexture(btn)
    SetRoundBackdrop(btn, T.btnBg, T.btnBorder)

    if btn.GetFontString then
        local fs = btn:GetFontString()
        if fs then
            fs:SetFont(GetFont(), 10, "OUTLINE")
            fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
        end
    end

    local origEnter = btn:GetScript("OnEnter")
    btn:SetScript("OnEnter", function()
        SetRoundBackdrop(this, T.btnHoverBg, T.btnHoverBd)
        if this.GetFontString then
            local tfs = this:GetFontString()
            if tfs then tfs:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end
        end
        if origEnter then origEnter() end
    end)
    local origLeave = btn:GetScript("OnLeave")
    btn:SetScript("OnLeave", function()
        SetRoundBackdrop(this, T.btnBg, T.btnBorder)
        if this.GetFontString then
            local tfs = this:GetFontString()
            if tfs then tfs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) end
        end
        if origLeave then origLeave() end
    end)
end

local function IsPfQuestButtonText(text)
    if not text then return false end
    return string.find(text, "show") or string.find(text, "hide")
        or string.find(text, "clean") or string.find(text, "reset")
        or string.find(text, "Show") or string.find(text, "Hide")
        or string.find(text, "Clean") or string.find(text, "Reset")
        or string.find(text, "显示") or string.find(text, "隐藏")
        or string.find(text, "清空") or string.find(text, "重置")
end

local function TrySkinPfQuestButtons()
    local pfBtns = {}

    for _, name in ipairs({
        "pfQuestShow", "pfQuestHide", "pfQuestClean", "pfQuestReset",
        "pfQuest.show", "pfQuest.hide", "pfQuest.clean", "pfQuest.reset",
    }) do
        local btn = _G[name]
        if btn then
            SkinPfQuestButton(btn)
            table.insert(pfBtns, btn)
        end
    end

    if pfQuest and pfQuest.buttons then
        for _, btn in pairs(pfQuest.buttons) do
            if type(btn) == "table" and btn.GetObjectType then
                SkinPfQuestButton(btn)
                table.insert(pfBtns, btn)
            end
        end
    end

    local detailChild = _G["QuestLogDetailScrollFrameChildFrame"]
        or _G["QuestLogDetailScrollFrameChild"]
    if detailChild and detailChild.GetChildren then
        local children = { detailChild:GetChildren() }
        for idx = 1, table.getn(children) do
            local child = children[idx]
            if child and child.GetObjectType and child:GetObjectType() == "Button" and child.GetFontString then
                local fs = child:GetFontString()
                if fs then
                    local text = fs:GetText()
                    if IsPfQuestButtonText(text) then
                        SkinPfQuestButton(child)
                        table.insert(pfBtns, child)
                    end
                end
            end
        end
    end

    -- Resize pfquest buttons to fit within the detail content area (keep original positions)
    local contentW = FRAME_W - LIST_W - DETAIL_PAD * 2 - 4 - INNER_PAD * 2 - SCROLL_W - 6
    local btnCount = table.getn(pfBtns)
    if btnCount > 0 and contentW > 100 then
        local gap = 2
        local pfBtnW = math.floor((contentW - gap * (btnCount - 1)) / btnCount)
        if pfBtnW < 50 then pfBtnW = 50 end
        for bi = 1, btnCount do
            local btn = pfBtns[bi]
            if btn and btn.SetWidth then
                btn:SetWidth(pfBtnW)
            end
        end
    end
end

--------------------------------------------------------------------------------
-- Quest Tracker Button Skinning
--------------------------------------------------------------------------------
local function SkinQuestTrackButton()
    for _, bname in ipairs({
        "QuestLogTrack", "QuestLogFrameTrackButton", "QuestLogTrackButton",
    }) do
        local trackBtn = _G[bname]
        if trackBtn then
            trackBtn:Hide()
            trackBtn:SetAlpha(0)
            trackBtn:SetWidth(1)
            trackBtn:SetHeight(1)
            trackBtn:ClearAllPoints()
            trackBtn:SetPoint("TOPLEFT", QuestLogFrame, "TOPLEFT", -9999, 0)
        end
    end
    for _, tname in ipairs({
        "QuestLogTrackText", "QuestLogTrackButtonText",
        "QuestLogTrackHighlight",
    }) do
        local t = _G[tname]
        if t then
            t:Hide()
            if t.SetAlpha then t:SetAlpha(0) end
        end
    end
end

--------------------------------------------------------------------------------
-- Hooks
--------------------------------------------------------------------------------
local function ClampHighlightWidth()
    local hl = _G["QuestLogHighlightFrame"]
    if hl and hl.IsVisible and hl:IsVisible() then
        hl:SetWidth(LIST_BTN_W)
    end
end

local function EnforceListScrollSize()
    local lf = QuestLogListScrollFrame
    local f = QuestLogFrame
    if not lf or not f or not f._nanamiListPanel then return end
    local panelH = f._nanamiListPanel:GetHeight()
    if panelH and panelH > 50 then
        lf:SetHeight(panelH - INNER_PAD - 4)
    end
end

local function InstallHooks()
    local origUpdate = QuestLog_Update
    if origUpdate then
        QuestLog_Update = function()
            origUpdate()
            if QuestLogFrame then QuestLogFrame:SetWidth(FRAME_W) end
            EnforceListScrollSize()
            StyleQuestListEntries()
            ClampHighlightWidth()
            if not pfquestSkinned then
                pfquestSkinned = true
                TrySkinPfQuestButtons()
            end
        end
    end

    local origSetSelection = QuestLog_SetSelection
    if origSetSelection then
        QuestLog_SetSelection = function(index)
            origSetSelection(index)
            EnforceListScrollSize()
            StyleQuestListEntries()
            ClampHighlightWidth()
            StyleQuestDetailText()
            TrySkinPfQuestButtons()
            if QuestLogFrame and QuestLogFrame._skinExtraButtons then
                QuestLogFrame._skinExtraButtons()
            end
            local sb = _G["QuestLogFramePushQuestButton"] or _G["QuestFramePushQuestButton"]
            if sb and sb._nanamiRefreshShare then sb._nanamiRefreshShare(sb) end
        end
    end

    local origUpdateDetails = QuestLog_UpdateQuestDetails
    if origUpdateDetails then
        QuestLog_UpdateQuestDetails = function(doNotShow)
            origUpdateDetails(doNotShow)
            StyleQuestDetailText()
            TrySkinPfQuestButtons()
            if QuestLogFrame and QuestLogFrame._skinExtraButtons then
                QuestLogFrame._skinExtraButtons()
            end
        end
    end
end

--------------------------------------------------------------------------------
-- Initialize
--------------------------------------------------------------------------------
function QLS:Initialize()
    if skinApplied then return end
    if not QuestLogFrame then return end
    skinApplied = true

    SkinMainFrame()
    SkinQuestList()
    SkinQuestDetail()
    SkinBottomButtons()
    SkinQuestTrackButton()
    InstallHooks()

    local origOnShow = QuestLogFrame:GetScript("OnShow")
    QuestLogFrame:SetScript("OnShow", function()
        if origOnShow then origOnShow() end
        QuestLogFrame:SetWidth(FRAME_W)
        EnforceListScrollSize()
        StyleQuestListEntries()
        ClampHighlightWidth()
        StyleQuestDetailText()
        if not pfquestSkinned then
            pfquestSkinned = true
            TrySkinPfQuestButtons()
        end
        if QuestLogFrame._skinExtraButtons then
            QuestLogFrame._skinExtraButtons()
        end
    end)

    -- Delayed pfquest + translate button detection
    local pfCheck = CreateFrame("Frame", nil, QuestLogFrame)
    pfCheck._e = 0; pfCheck._n = 0
    pfCheck:SetScript("OnUpdate", function()
        this._e = (this._e or 0) + (arg1 or 0)
        if this._e < 0.5 then return end
        this._e = 0
        this._n = (this._n or 0) + 1
        TrySkinPfQuestButtons()
        if QuestLogFrame._skinExtraButtons then
            QuestLogFrame._skinExtraButtons()
        end
        if this._n >= 8 then this:SetScript("OnUpdate", nil) end
    end)

    if QuestLogFrame:IsVisible() then
        StyleQuestListEntries()
        StyleQuestDetailText()
    end
end

--------------------------------------------------------------------------------
-- Bootstrap
--------------------------------------------------------------------------------
local bootstrap = CreateFrame("Frame")
bootstrap:RegisterEvent("PLAYER_LOGIN")
bootstrap:SetScript("OnEvent", function()
    if event == "PLAYER_LOGIN" then
        if SFramesDB.enableQuestLogSkin == nil then
            SFramesDB.enableQuestLogSkin = true
        end
        if SFramesDB.enableQuestLogSkin ~= false then
            QLS:Initialize()
        end
    end
end)
