-- Modules/ElvUISkin.lua
-- ElvUI Skinning Module for BetterFriendlist
-- Adds native ElvUI skin support

local ADDON_NAME, BFL = ...

-- Register Module
local ElvUISkin = BFL:RegisterModule("ElvUISkin", {})

-- Helper to handle scrollbars across Retail and Classic
local function SkinScrollBar(S, scrollBar)
	if not scrollBar then
		return
	end

	-- Validation: Ensure scrollBar is an object
	if not scrollBar.IsObjectType then
		return
	end

	local isClassic = BFL and BFL.IsClassic

	if isClassic then
		-- Classic Override: Always use HandleScrollBar
		-- HandleTrimScrollBar does not exist or shouldn't be used in Classic environments
		if S.HandleScrollBar then
			S:HandleScrollBar(scrollBar)
		end
		return
	end

	-- Retail: Check for TrimScrollBar first
	if S.HandleTrimScrollBar then
		S:HandleTrimScrollBar(scrollBar)
	elseif S.HandleScrollBar then
		S:HandleScrollBar(scrollBar)
	end
end

-- Normalize Classic UIDropDownMenu hitbox/geometry after ElvUI skinning.
-- Without this, the clickable region can drift outside the visual box.
local function FixClassicDropdownHitbox(dropdown, width, height)
	if not (BFL and BFL.IsClassic and dropdown) then
		return
	end

	if width then
		dropdown.BFL_ClassicDropdownWidth = width
	end
	if height then
		dropdown.BFL_ClassicDropdownHeight = height
	end

	local targetWidth = dropdown.BFL_ClassicDropdownWidth
	local targetHeight = dropdown.BFL_ClassicDropdownHeight

	if targetWidth and UIDropDownMenu_SetWidth then
		UIDropDownMenu_SetWidth(dropdown, targetWidth)
	end
	if targetHeight then
		dropdown:SetHeight(targetHeight)
	end

	local ddName = dropdown.GetName and dropdown:GetName()
	if not ddName then
		return
	end

	local button = _G[ddName .. "Button"]
	local text = _G[ddName .. "Text"]
	if button then
		button:ClearAllPoints()
		button:SetAllPoints(dropdown)
		button:SetHitRectInsets(0, 0, 0, 0)
		if targetHeight then
			button:SetHeight(targetHeight)
		end
	end

	if text and button then
		text:ClearAllPoints()
		text:SetPoint("LEFT", dropdown, "LEFT", 8, 0)
		text:SetPoint("RIGHT", button, "RIGHT", -20, 0)
		text:SetJustifyH("LEFT")
		text:SetWordWrap(false)
	end

	if not dropdown.BFL_ClassicDropdownHookInstalled then
		dropdown.BFL_ClassicDropdownHookInstalled = true
		if dropdown.HookScript then
			dropdown:HookScript("OnShow", function(self)
				C_Timer.After(0, function()
					if self and self.GetName then
						FixClassicDropdownHitbox(self)
					end
				end)
			end)
		end
		if button and button.HookScript then
			button:HookScript("OnClick", function()
				C_Timer.After(0, function()
					if dropdown and dropdown.GetName then
						FixClassicDropdownHitbox(dropdown)
					end
				end)
			end)
		end
	end
end

local function IsBFLTab(tab)
	local name = tab and tab.GetName and tab:GetName()
	return name
		and (
			string.find(name, "BetterFriendsFrameTab", 1, true)
			or string.find(name, "BetterFriendlistSettingsFrameTab", 1, true)
			or string.find(name, "BetterFriendsFrameBottomTab", 1, true)
		)
end

local function CenterBFLTabText(tab)
	if not IsBFLTab(tab) then
		return
	end

	local text = tab.Text or (tab.GetFontString and tab:GetFontString())
	if not text then
		return
	end

	text:ClearAllPoints()
	text:SetPoint("CENTER", tab, "CENTER", 0, 0)
	text:SetJustifyH("CENTER")
	text:SetJustifyV("MIDDLE")
end

local function CenterNamedTabs(prefix, count)
	for i = 1, count do
		CenterBFLTabText(_G[prefix .. i])
	end
end

local function CenterMainFrameTabs()
	CenterNamedTabs("BetterFriendsFrameTab", 4)
	CenterNamedTabs("BetterFriendsFrameBottomTab", 4)
end

local function DeferCenterBFLTab(tab)
	if C_Timer and C_Timer.After then
		C_Timer.After(0, function()
			CenterBFLTabText(tab)
		end)
	else
		CenterBFLTabText(tab)
	end
end

local function HookBFLTabCenter(tab)
	if not IsBFLTab(tab) or tab.BFL_ElvCenterHooked or not tab.HookScript then
		return
	end

	tab:HookScript("OnShow", CenterBFLTabText)
	tab:HookScript("OnSizeChanged", CenterBFLTabText)
	tab:HookScript("OnClick", DeferCenterBFLTab)
	tab.BFL_ElvCenterHooked = true
end

local function HookNamedTabs(prefix, count)
	for i = 1, count do
		HookBFLTabCenter(_G[prefix .. i])
	end
end

function ElvUISkin:Initialize()
	-- Check if ElvUI is loaded immediately
	if BFL.IsElvUIAvailable and BFL:IsElvUIAvailable() then
		self:RegisterSkin()
	else
		-- Wait for ElvUI to load (in case BFL loads first)
		-- Check for "ElvUI" or "ElvUI_Classic" or a valid ElvUI engine.
		local listener = CreateFrame("Frame")
		listener:RegisterEvent("ADDON_LOADED")
		listener:SetScript("OnEvent", function(f, event, addonName)
			if addonName == "ElvUI" or addonName == "ElvUI_Classic" or (BFL.IsElvUIAvailable and BFL:IsElvUIAvailable()) then
				if self:RegisterSkin() ~= false then
					f:UnregisterEvent("ADDON_LOADED")
				end
			end
		end)
	end
end

function ElvUISkin:RegisterSkin()
	local E = BFL.GetElvUIEngine and BFL:GetElvUIEngine(false)
	if not E then
		return false
	end

	local isEnabled = BFL.IsThemeActive and BFL:IsThemeActive("elvui")
	if not isEnabled then
		-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Skin disabled in theme settings")
		return
	end

	-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Registering skin...")
	local RealS = E:GetModule("Skins")
	if not RealS then
		-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Skins module not found!")
		return false
	end

	-- Create Safety Proxy to prevent nil value crashes in ElvUI Skins module
	local S = setmetatable({}, {
		__index = function(t, k)
			local val = RealS[k]
			if type(val) == "function" then
				return function(_, arg1, ...)
					-- Protect Handlers from nil arguments
					if
						arg1 == nil
						and (
							k == "HandleButton"
							or k == "HandleCheckBox"
							or k == "HandleEditBox"
							or k == "HandleTab"
							or k == "HandleScrollBar"
							or k == "HandleDropDownBox"
							or k == "HandlePortraitFrame"
						)
					then
						-- Silently ignore nil calls to prevent crashes
						return
					end
					return val(RealS, arg1, ...) -- Pass RealS as self
				end
			else
				return val
			end
		end,
		__newindex = function(t, k, v)
			RealS[k] = v
		end,
	})

	-- Register callback for skinning
	-- This ensures our skin runs when ElvUI skins are applied
	-- Try both typical addon names to be safe
	if S.AddCallbackForAddon then
		S:AddCallbackForAddon("BetterFriendlist", "BetterFriendlist", function()
			-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Callback triggered")
			xpcall(function()
				self:SkinFrames(E, S)
			end, function(err)
				-- BFL:DebugPrint("|cffff0000BetterFriendlist ElvUI Skin Error:|r " .. tostring(err))
			end)
		end)
	end

	-- Force run if ElvUI is already initialized (Classic fix)
	if E.initialized then
		-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Direct call triggered (E.initialized=true)")
		xpcall(function()
			self:SkinFrames(E, S)
		end, function(err)
			-- BFL:DebugPrint("|cffff0000BetterFriendlist ElvUI Skin Error:|r " .. tostring(err))
		end)
	else
		-- BFL:DebugPrint("|cff00ffffBFL ElvUI:|r Direct call skipped (E.initialized=false)")
	end

	return true
end

function ElvUISkin:SkinFrames(E, S)
	if not _G.BetterFriendsFrame then
		return
	end

	-- Ensure Tab Text is centered (Hook for updates)
	if not self.TabHookInstalled then
		-- On 12.0.0+ (HasSecretValues), global PanelTemplates hooks taint the
		-- execution context, causing "secret string conversion" errors in the
		-- chat system. Use per-tab hooks and BFL-owned tab functions there.
		HookNamedTabs("BetterFriendsFrameTab", 4)
		HookNamedTabs("BetterFriendsFrameBottomTab", 4)
		HookNamedTabs("BetterFriendlistSettingsFrameTab", 10)

		if not BFL.HasSecretValues then
			if _G.PanelTemplates_SelectTab then
				hooksecurefunc("PanelTemplates_SelectTab", CenterBFLTabText)
			end
			if _G.PanelTemplates_DeselectTab then
				hooksecurefunc("PanelTemplates_DeselectTab", CenterBFLTabText)
			end
		end

		if hooksecurefunc then
			if type(_G.BetterFriendsFrame_ShowTab) == "function" then
				hooksecurefunc("BetterFriendsFrame_ShowTab", CenterMainFrameTabs)
			end
			if type(_G.BetterFriendsFrame_ShowBottomTab) == "function" then
				hooksecurefunc("BetterFriendsFrame_ShowBottomTab", CenterMainFrameTabs)
			end
			if type(BFL.ApplyTabFonts) == "function" then
				hooksecurefunc(BFL, "ApplyTabFonts", CenterMainFrameTabs)
			end
		end

		self.TabHookInstalled = true
	end

	-- BFL:DebugPrint("ElvUISkin: SkinFrames started")
	local frame = _G.BetterFriendsFrame

	-- Skin Main Frame
	-- BFL:DebugPrint("ElvUISkin: Skinning Main Frame")
	if frame.PortraitContainer or frame.portrait then
		-- Use pcall to safeguard against ElvUI PixelPerfect errors (nil comparisons)
		-- in case the frame isn't fully dimensioned yet
		pcall(function()
			S:HandlePortraitFrame(frame)
		end)
	end

	-- Skin Portrait Button (Changelog)
	if frame.PortraitButton then
		-- BFL:DebugPrint("ElvUISkin: Skinning PortraitButton")
		local button = frame.PortraitButton

		-- Classic: Hide portrait when ElvUI active and NOT in Simple Mode
		-- (Changelog will be accessible via Contacts Menu instead)
		local shouldSkinPortrait = true
		if BFL.IsClassic then
			local DB = BFL:GetModule("DB")
			local simpleMode = DB and DB:Get("simpleMode", false) or false
			if not simpleMode then
				button:Hide()
				shouldSkinPortrait = false
			end
		end

		if shouldSkinPortrait then
			-- Reset position and size to fit ElvUI style
			button:ClearAllPoints()
			button:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4)
			button:SetSize(42, 42) -- Standard ElvUI icon size (square)
			button:SetFrameLevel(frame:GetFrameLevel() + 5)

			-- Create Backdrop
			button:CreateBackdrop("Transparent")

			-- Handle Icon
			if BFL.IsClassic then
				-- Classic: Hide the old circular icon and create a new square one
				if button.Icon then
					button.Icon:Hide()
				end

				-- Create new square icon without mask
				if not button.ElvUIIcon then
					button.ElvUIIcon = button:CreateTexture(nil, "ARTWORK")
					button.ElvUIIcon:SetTexture("Interface\\AddOns\\BetterFriendlist\\Textures\\PortraitIcon.blp")
				end
				button.ElvUIIcon:ClearAllPoints()
				button.ElvUIIcon:SetInside(button.backdrop)
				button.ElvUIIcon:SetTexCoord(unpack(E.TexCoords)) -- Square crop
				button.ElvUIIcon:Show()

				-- Reference for consistency
				button.Icon = button.ElvUIIcon
			elseif not button.Icon then
				-- Retail: Create a new texture
				button.Icon = button:CreateTexture(nil, "ARTWORK")
				button.Icon:SetInside(button.backdrop)
				button.Icon:SetTexture("Interface\\AddOns\\BetterFriendlist\\Textures\\PortraitIcon.blp")
				button.Icon:SetTexCoord(unpack(E.TexCoords))
				button.Icon:Show()
			end

			-- Hide original icon and mask (if different from button.Icon)
			if frame.PortraitIcon and frame.PortraitIcon ~= button.Icon then
				frame.PortraitIcon:Hide()
			end
			if frame.PortraitMask then
				frame.PortraitMask:Hide()
			end

			-- Handle Glow (New Version Indicator)
			if button.Glow then
				button.Glow:SetParent(button)
				button.Glow:ClearAllPoints()
				button.Glow:SetInside(button.backdrop)
				button.Glow:SetDrawLayer("OVERLAY")
				-- Use a cleaner glow texture for ElvUI
				button.Glow:SetTexture(E.Media.Textures.Highlight)
				button.Glow:SetVertexColor(1, 0.82, 0, 0.5)
			end

			-- Add Hover Effect
			button:HookScript("OnEnter", function(self)
				if self.backdrop then
					local color = E.media.rgbvaluecolor
					if color then
						self.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
					end
				end
			end)

			button:HookScript("OnLeave", function(self)
				if self.backdrop then
					local color = E.media.bordercolor
					if color then
						self.backdrop:SetBackdropBorderColor(unpack(color))
					end
				end
			end)
		end
	end

	-- Skin Tabs (Top)
	BFL:DebugPrint("ElvUISkin: Skinning Top Tabs")
	for i = 1, 4 do
		local tab = _G["BetterFriendsFrameTab" .. i]
		if tab then
			S:HandleTab(tab)
			HookBFLTabCenter(tab)

			-- Adjust text position
			local text = tab.Text or (tab.GetFontString and tab:GetFontString())
			if text then
				CenterBFLTabText(tab)
				local textHeight = text:GetStringHeight() or 0
				local tabHeight = math.max(32, textHeight + 20)
				tab:SetHeight(tabHeight)
			else
				tab:SetHeight(25)
			end
		end
	end

	-- Skin Tabs (Bottom)
	BFL:DebugPrint("ElvUISkin: Skinning Bottom Tabs")
	if BFL.IsClassic then
		-- Classic: skin all existing bottom tabs (Friends/Who/Guild/Raid) and compact spacing.
		local frameWidth = frame:GetWidth()
		if frameWidth <= 0 then
			frameWidth = 338
		end

		local tabs = {}
		for i = 1, 4 do
			local tab = _G["BetterFriendsFrameBottomTab" .. i]
			if tab then
				table.insert(tabs, tab)
			end
		end

		local numTabs = #tabs
		if numTabs > 0 then
			local spacing = -4
			local tabWidth = math.floor((frameWidth - (spacing * (numTabs - 1))) / numTabs)
			for i, tab in ipairs(tabs) do
				S:HandleTab(tab)
				HookBFLTabCenter(tab)
				tab:SetHeight(28)
				tab:SetWidth(tabWidth)
				tab:ClearAllPoints()
				if i == 1 then
					tab:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 0, 1)
				else
					local prevTab = tabs[i - 1]
					tab:SetPoint("LEFT", prevTab, "RIGHT", spacing, 0)
				end
				CenterBFLTabText(tab)
			end
		end
	else
		for i = 1, 4 do
			local tab = _G["BetterFriendsFrameBottomTab" .. i]
			if tab then
				S:HandleTab(tab)
				HookBFLTabCenter(tab)
				tab:SetHeight(28)
				tab:ClearAllPoints()
				if i == 1 then
					tab:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", -2, 1)
				else
					local prevTab = _G["BetterFriendsFrameBottomTab" .. (i - 1)]
					tab:SetPoint("LEFT", prevTab, "RIGHT", -5, 0)
				end
				CenterBFLTabText(tab)
			end
		end
	end

	-- Skin Insets
	BFL:DebugPrint("ElvUISkin: Skinning Insets")
	if frame.Inset then
		frame.Inset:StripTextures()
		frame.Inset:CreateBackdrop("Transparent")
	end

	if frame.ListInset then
		frame.ListInset:StripTextures()
		frame.ListInset:CreateBackdrop("Transparent")
	end

	-- Skin WhoFrame Inset
	if frame.WhoFrame and frame.WhoFrame.ListInset then
		frame.WhoFrame.ListInset:StripTextures()
		frame.WhoFrame.ListInset:CreateBackdrop("Transparent")
	end

	-- Skin RecruitAFriendFrame
	BFL:DebugPrint("ElvUISkin: Skinning RAF")
	self:SkinRecruitAFriend(E, S, frame)

	-- Skin RecentAlliesFrame ScrollBar
	BFL:DebugPrint("ElvUISkin: Skinning RecentAllies")
	if frame.RecentAlliesFrame and frame.RecentAlliesFrame.ScrollBar then
		SkinScrollBar(S, frame.RecentAlliesFrame.ScrollBar)
	end

	-- Skin IgnoreListWindow
	BFL:DebugPrint("ElvUISkin: Skinning IgnoreList")
	if frame.IgnoreListWindow then
		S:HandlePortraitFrame(frame.IgnoreListWindow)

		if frame.IgnoreListWindow.Inset then
			frame.IgnoreListWindow.Inset:StripTextures()
			frame.IgnoreListWindow.Inset:CreateBackdrop("Transparent")
		end

		if frame.IgnoreListWindow.ScrollBar then
			SkinScrollBar(S, frame.IgnoreListWindow.ScrollBar)
		end

		if frame.IgnoreListWindow.UnignorePlayerButton then
			S:HandleButton(frame.IgnoreListWindow.UnignorePlayerButton)
		end

		-- Skin Global Ignore List Button (if active)
		if frame.IgnoreListWindow.GlobalIgnoreListButton then
			-- Fix: Check if GlobalIgnoreListButton is actually a button (it might be a frame in some cases)
			if frame.IgnoreListWindow.GlobalIgnoreListButton:IsObjectType("Button") then
				S:HandleButton(frame.IgnoreListWindow.GlobalIgnoreListButton)

				-- Preserve the Icon (HandleButton calls StripTextures which hides ARTWORK)
				if frame.IgnoreListWindow.GlobalIgnoreListButton.Icon then
					-- Move to OVERLAY to ensure it sits on top of the new backdrop
					frame.IgnoreListWindow.GlobalIgnoreListButton.Icon:SetDrawLayer("OVERLAY")

					-- Ensure it is visible
					frame.IgnoreListWindow.GlobalIgnoreListButton.Icon:SetAlpha(1)
					frame.IgnoreListWindow.GlobalIgnoreListButton.Icon:Show()
				end
			end
		end

		-- Skin EnhanceQoL Ignore List Button (if active)
		if frame.IgnoreListWindow.EnhanceQoLIgnoreButton then
			if frame.IgnoreListWindow.EnhanceQoLIgnoreButton:IsObjectType("Button") then
				S:HandleButton(frame.IgnoreListWindow.EnhanceQoLIgnoreButton)

				if frame.IgnoreListWindow.EnhanceQoLIgnoreButton.Icon then
					frame.IgnoreListWindow.EnhanceQoLIgnoreButton.Icon:SetDrawLayer("OVERLAY")
					frame.IgnoreListWindow.EnhanceQoLIgnoreButton.Icon:SetAlpha(1)
					frame.IgnoreListWindow.EnhanceQoLIgnoreButton.Icon:Show()
				end
			end
		end
	end

	-- Skin ScrollBars
	BFL:DebugPrint("ElvUISkin: Skinning ScrollBars")
	-- Friends List ScrollBar - Point 7

	-- Check for Retail Minimal, Standard, or Classic ScrollBar (often on ScrollFrame)
	local scrollBar = frame.MinimalScrollBar or frame.ScrollBar
	if not scrollBar and frame.ScrollFrame then
		-- Classic FauxScrollFrame often names it $parentScrollBar
		if frame.ScrollFrame.ScrollBar then
			scrollBar = frame.ScrollFrame.ScrollBar
		elseif frame.ScrollFrame:GetName() then
			scrollBar = _G[frame.ScrollFrame:GetName() .. "ScrollBar"]
		end
	end

	-- Explicit Check for Classic Manual ScrollBar (Fix Phase 27)
	if not scrollBar and BFL.IsClassic then
		local classicSB = _G["BetterFriendsClassicScrollFrameScrollBar"]
		if classicSB then
			scrollBar = classicSB
		end
	end

	if scrollBar then
		-- Use specific handler if available
		if frame.MinimalScrollBar and S.HandleMinimalScrollBar then
			pcall(S.HandleMinimalScrollBar, S, frame.MinimalScrollBar)
		else
			-- Fix: Wrap ScrollBar skinning in pcall to prevent crashes on malformed scrollbars
			pcall(SkinScrollBar, S, scrollBar)
		end
	else
		-- Classic: Hook InitializeClassicScrollFrame to skin ScrollBar immediately after creation
		if BFL.IsClassic then
			local FriendsList = BFL:GetModule("FriendsList")
			if FriendsList and FriendsList.InitializeClassicScrollFrame then
				hooksecurefunc(FriendsList, "InitializeClassicScrollFrame", function(self, scrollFrame)
					-- ScrollBar is created by FauxScrollFrameTemplate with name $parentScrollBar
					if scrollFrame and scrollFrame.FauxScrollFrame then
						local classicScrollBar = _G["BetterFriendsClassicScrollFrameScrollBar"]
						if classicScrollBar and not classicScrollBar.isSkinned then
							SkinScrollBar(S, classicScrollBar)
							classicScrollBar.isSkinned = true
							BFL:DebugPrint("ElvUISkin: Classic ScrollBar skinned")
						end
					end
				end)
			end
		end
	end

	-- Who Frame ScrollBar
	if frame.WhoFrame and frame.WhoFrame.ScrollBar then
		SkinScrollBar(S, frame.WhoFrame.ScrollBar)
	end

	-- Raid Frame ScrollBar
	if frame.RaidFrame and frame.RaidFrame.ScrollBar then
		SkinScrollBar(S, frame.RaidFrame.ScrollBar)
	end

	-- Skin Buttons
	BFL:DebugPrint("ElvUISkin: Skinning Buttons")
	-- Add Friend / Send Who / etc
	if frame.AddFriendButton then
		S:HandleButton(frame.AddFriendButton)
	end
	if frame.SendMessageButton then
		S:HandleButton(frame.SendMessageButton)
	end
	if frame.RecruitmentButton then
		S:HandleButton(frame.RecruitmentButton)
	end

	-- Skin HelpButton
	if frame.HelpButton then
		-- Do not skin the framework of the HelpButton, only color the icon
		-- S:HandleButton(frame.HelpButton)
		if frame.HelpButton.Icon then
			frame.HelpButton.Icon:SetVertexColor(1, 1, 1)
		end
	end

	-- Point 2: MenuButton & SettingsButton
	if frame.FriendsTabHeader and frame.FriendsTabHeader.BattlenetFrame then
		if frame.FriendsTabHeader.BattlenetFrame.ContactsMenuButton then
			pcall(S.HandleButton, S, frame.FriendsTabHeader.BattlenetFrame.ContactsMenuButton)
		end
		if frame.FriendsTabHeader.BattlenetFrame.SettingsButton then
			pcall(S.HandleButton, S, frame.FriendsTabHeader.BattlenetFrame.SettingsButton)
		end

		-- Classic: Reposition buttons 15px to the right (already anchored to bnet, which moved)
		-- No additional changes needed as they inherit bnet's new position
	end

	if frame.WhoFrame then
		if frame.WhoFrame.WhoButton then
			pcall(S.HandleButton, S, frame.WhoFrame.WhoButton)
		end
		if frame.WhoFrame.AddFriendButton then
			pcall(S.HandleButton, S, frame.WhoFrame.AddFriendButton)
		end
		if frame.WhoFrame.GroupInviteButton then
			pcall(S.HandleButton, S, frame.WhoFrame.GroupInviteButton)
		end

		-- EditBox
		if frame.WhoFrame.EditBox then
			S:HandleEditBox(frame.WhoFrame.EditBox)
			if frame.WhoFrame.EditBox.Backdrop then
				frame.WhoFrame.EditBox.Backdrop:StripTextures()
				frame.WhoFrame.EditBox.Backdrop:CreateBackdrop("Transparent")
			end
		end

		-- Dropdown
		if frame.WhoFrame.ColumnDropdown then
			S:HandleDropDownBox(frame.WhoFrame.ColumnDropdown)

			-- Classic: Fix text clipping into arrow and restore selected value
			if BFL.IsClassic then
				local dropdown = frame.WhoFrame.ColumnDropdown
				local ddName = dropdown:GetName()
				if ddName then
					local ddText = _G[ddName .. "Text"]
					local ddButton = _G[ddName .. "Button"]
					if ddText and ddButton then
						ddText:ClearAllPoints()
						ddText:SetPoint("LEFT", dropdown, "LEFT", 5, 2)
						ddText:SetPoint("RIGHT", ddButton, "LEFT", -2, 0)
						ddText:SetJustifyH("LEFT")
						ddText:SetWordWrap(false)
					end
				end
				-- Restore selected value text after skinning
				local WhoFrameModule = BFL:GetModule("WhoFrame")
				if WhoFrameModule and WhoFrameModule.GetSortValue then
					local sortValue = WhoFrameModule:GetSortValue() or 1
					local selectionTexts = { ZONE, GUILD, RACE }
					UIDropDownMenu_SetText(dropdown, selectionTexts[sortValue] or ZONE)
				end
			end
		end
	end

	-- Skin TabHeader Elements
	BFL:DebugPrint("ElvUISkin: Skinning TabHeader")
	if frame.FriendsTabHeader then
		-- Battlenet Frame & Broadcast Frame
		if frame.FriendsTabHeader.BattlenetFrame then
			local bnet = frame.FriendsTabHeader.BattlenetFrame

			-- Skin Main Frame
			bnet:StripTextures()
			bnet:CreateBackdrop("Transparent")
			bnet.backdrop:SetPoint("TOPLEFT", 0, 0)
			bnet.backdrop:SetPoint("BOTTOMRIGHT", 0, 0)

			-- Classic: Reduce width to make room for StatusDropdown
			if BFL.IsClassic then
				bnet:SetWidth(180)
				-- Reposition 62px from right edge (use same anchor as Core.lua for consistency)
				bnet:ClearAllPoints()
				bnet:SetPoint("TOPRIGHT", frame.FriendsTabHeader, "TOPRIGHT", -62, -27)
			end

			if bnet.Tag then
				bnet.Tag:SetParent(bnet.backdrop)
			end

			-- Set initial border color to default (not blue)
			if E.media and E.media.bordercolor then
				bnet.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
			end

			-- Add Hover Effect (like ElvUI)
			bnet:EnableMouse(true)
			bnet:SetScript("OnEnter", function(self)
				if self.backdrop then
					local c = _G.FRIENDS_BNET_NAME_COLOR
					if c then
						self.backdrop:SetBackdropBorderColor(c.r, c.g, c.b)
					end
				end
			end)

			bnet:SetScript("OnLeave", function(self)
				if self.backdrop then
					local c = E.media.bordercolor
					if c then
						self.backdrop:SetBackdropBorderColor(unpack(c))
					end
				end
			end)

			if bnet.BroadcastFrame then
				bnet.BroadcastFrame:StripTextures()
				bnet.BroadcastFrame:CreateBackdrop("Transparent")

				if bnet.BroadcastFrame.UpdateButton then
					S:HandleButton(bnet.BroadcastFrame.UpdateButton)
				end
				if bnet.BroadcastFrame.CancelButton then
					S:HandleButton(bnet.BroadcastFrame.CancelButton)
				end
				if bnet.BroadcastFrame.EditBox then
					S:HandleEditBox(bnet.BroadcastFrame.EditBox)
				end
			end

			if bnet.UnavailableInfoFrame then
				bnet.UnavailableInfoFrame:StripTextures()
				bnet.UnavailableInfoFrame:CreateBackdrop("Transparent")
			end
		end

		-- SearchBox
		if frame.FriendsTabHeader.SearchBox then
			S:HandleEditBox(frame.FriendsTabHeader.SearchBox)

			-- Classic: Position below dropdowns
			if BFL.IsClassic then
				frame.FriendsTabHeader.SearchBox:ClearAllPoints()
				frame.FriendsTabHeader.SearchBox:SetPoint(
					"TOP",
					frame.FriendsTabHeader.BattlenetFrame,
					"BOTTOM",
					0,
					-35
				)
				frame.FriendsTabHeader.SearchBox:SetPoint("LEFT", frame.Inset, "LEFT", 10, 0)
				frame.FriendsTabHeader.SearchBox:SetPoint("RIGHT", frame.Inset, "RIGHT", -10, 0)
			end
		end

		-- Dropdowns - Point 3: Fix width & Layout (Classic adjustments)
		-- Common function to skin and size dropdowns
		local function SkinAndSizeDropdown(dropdown, width, height)
			if not dropdown then
				return
			end
			if S.HandleDropDownBox then
				S:HandleDropDownBox(dropdown, width)
			end

			-- Classic uses UIDropDownMenu, Retail uses modern dropdown
			if BFL.IsClassic and UIDropDownMenu_SetWidth then
				UIDropDownMenu_SetWidth(dropdown, width)
			else
				dropdown:SetWidth(width)
			end
			dropdown:SetHeight(height)

			-- Also force the button to match height if needed
			local name = dropdown:GetName()
			if name then
				local button = _G[name .. "Button"]
				if button then
					button:SetHeight(height)
				end
			end
		end

		if frame.FriendsTabHeader.StatusDropdown then
			if BFL.IsClassic then
				-- Classic: Keep visual width at 38px but expand clickable area
				local dropdown = frame.FriendsTabHeader.StatusDropdown

				if S.HandleDropDownBox then
					S:HandleDropDownBox(dropdown, 38)
				end

				FixClassicDropdownHitbox(dropdown, 38, 24)

				-- Reposition: 1px gap left of BattlenetFrame
				dropdown:ClearAllPoints()
				dropdown:SetPoint("RIGHT", frame.FriendsTabHeader.BattlenetFrame, "LEFT", -1, 0)
			else
				SkinAndSizeDropdown(frame.FriendsTabHeader.StatusDropdown, 70, 22)
			end
		end

		if frame.FriendsTabHeader.QuickFilterDropdown then
			if BFL.IsClassic then
				-- Classic: Re-anchor with clearer spacing to avoid visual clipping with sort dropdowns.
				local dropdown = frame.FriendsTabHeader.QuickFilterDropdown
				if S.HandleDropDownBox then
					S:HandleDropDownBox(dropdown)
				end
				FixClassicDropdownHitbox(dropdown, 70, 24)
				-- Restore position (matches FriendsList.lua Classic layout)
				if frame.FriendsTabHeader.SearchBox then
					dropdown:ClearAllPoints()
					dropdown:SetPoint("TOPLEFT", frame.FriendsTabHeader.SearchBox, "TOPLEFT", -16, 32)
				end
			else
				-- Retail: Use smaller width (50) to fit in one row
				SkinAndSizeDropdown(frame.FriendsTabHeader.QuickFilterDropdown, 50, 30)
			end
		end

		if frame.FriendsTabHeader.PrimarySortDropdown then
			if BFL.IsClassic then
				-- Classic: add spacing so controls don't overlap after skinning.
				local dropdown = frame.FriendsTabHeader.PrimarySortDropdown
				if S.HandleDropDownBox then
					S:HandleDropDownBox(dropdown)
				end
				FixClassicDropdownHitbox(dropdown, 70, 24)
				-- Anchor to QuickFilter with positive spacing.
				if frame.FriendsTabHeader.QuickFilterDropdown then
					dropdown:ClearAllPoints()
					dropdown:SetPoint("LEFT", frame.FriendsTabHeader.QuickFilterDropdown, "RIGHT", 6, 0)
				end
			else
				-- Retail: Keep existing size
				SkinAndSizeDropdown(frame.FriendsTabHeader.PrimarySortDropdown, 50, 30)

				-- Anchor to QuickFilter with positive spacing (ElvUI removes the transparent padding)
				frame.FriendsTabHeader.PrimarySortDropdown:ClearAllPoints()
				frame.FriendsTabHeader.PrimarySortDropdown:SetPoint(
					"LEFT",
					frame.FriendsTabHeader.QuickFilterDropdown,
					"RIGHT",
					5,
					0
				)
			end
		end

		if frame.FriendsTabHeader.SecondarySortDropdown then
			if BFL.IsClassic then
				-- Classic: add spacing so controls don't overlap after skinning.
				local dropdown = frame.FriendsTabHeader.SecondarySortDropdown
				if S.HandleDropDownBox then
					S:HandleDropDownBox(dropdown)
				end
				FixClassicDropdownHitbox(dropdown, 70, 24)
				-- Anchor to PrimarySort with positive spacing.
				if frame.FriendsTabHeader.PrimarySortDropdown then
					dropdown:ClearAllPoints()
					dropdown:SetPoint("LEFT", frame.FriendsTabHeader.PrimarySortDropdown, "RIGHT", 6, 0)
				end
			else
				-- Retail: Keep existing size
				SkinAndSizeDropdown(frame.FriendsTabHeader.SecondarySortDropdown, 50, 30)

				-- Anchor to PrimarySort
				frame.FriendsTabHeader.SecondarySortDropdown:ClearAllPoints()
				frame.FriendsTabHeader.SecondarySortDropdown:SetPoint(
					"LEFT",
					frame.FriendsTabHeader.PrimarySortDropdown,
					"RIGHT",
					5,
					0
				)
			end
		end
	end

	-- Skin Headers (Who Frame)
	BFL:DebugPrint("ElvUISkin: Skinning WhoFrame Headers")
	if frame.WhoFrame then
		local headers = { frame.WhoFrame.NameHeader, frame.WhoFrame.LevelHeader, frame.WhoFrame.ClassHeader }
		for _, header in ipairs(headers) do
			if header then
				S:HandleButton(header)
				header:SetHeight(22) -- Fixed height for headers
			end
		end

		-- Fix NameHeader alignment
		if frame.WhoFrame.NameHeader and frame.WhoFrame.ListInset then
			frame.WhoFrame.NameHeader:ClearAllPoints()
			frame.WhoFrame.NameHeader:SetPoint("BOTTOMLEFT", frame.WhoFrame.ListInset, "TOPLEFT", 0, 1)
		end

		-- Fix Dropdown height and alignment
		if frame.WhoFrame.ColumnDropdown then
			if BFL.IsClassic then
				FixClassicDropdownHitbox(frame.WhoFrame.ColumnDropdown, 110, 24)
			else
				frame.WhoFrame.ColumnDropdown:SetHeight(26) -- Match header height
			end

			-- Re-anchor to NameHeader
			frame.WhoFrame.ColumnDropdown:ClearAllPoints()
			frame.WhoFrame.ColumnDropdown:SetPoint("LEFT", frame.WhoFrame.NameHeader, "RIGHT", -1, 0)
		end

		-- Re-anchor LevelHeader
		if frame.WhoFrame.LevelHeader and frame.WhoFrame.ColumnDropdown then
			frame.WhoFrame.LevelHeader:ClearAllPoints()
			frame.WhoFrame.LevelHeader:SetPoint("LEFT", frame.WhoFrame.ColumnDropdown, "RIGHT", -1, 0)
		end

		-- Re-anchor ClassHeader
		if frame.WhoFrame.ClassHeader and frame.WhoFrame.LevelHeader then
			frame.WhoFrame.ClassHeader:ClearAllPoints()
			frame.WhoFrame.ClassHeader:SetPoint("LEFT", frame.WhoFrame.LevelHeader, "RIGHT", -1, 0)
		end
	end

	-- Skin QuickJoin
	BFL:DebugPrint("ElvUISkin: Skinning QuickJoin")
	if frame.QuickJoinFrame then
		if frame.QuickJoinFrame.ContentInset then
			frame.QuickJoinFrame.ContentInset:StripTextures()
			frame.QuickJoinFrame.ContentInset:CreateBackdrop("Transparent")

			if frame.QuickJoinFrame.ContentInset.ScrollBar then
				SkinScrollBar(S, frame.QuickJoinFrame.ContentInset.ScrollBar)
			end
		end

		-- Point 4: Join Queue Button (Check both possible paths)
		if frame.QuickJoinFrame.JoinQueueButton then
			S:HandleButton(frame.QuickJoinFrame.JoinQueueButton)
		elseif frame.QuickJoinFrame.ContentInset and frame.QuickJoinFrame.ContentInset.JoinQueueButton then
			S:HandleButton(frame.QuickJoinFrame.ContentInset.JoinQueueButton)
		end
	end

	-- Skin Raid Frame
	BFL:DebugPrint("ElvUISkin: Skinning RaidFrame")
	if frame.RaidFrame then
		-- Fix: Use GroupsInset instead of ListInset
		if frame.RaidFrame.GroupsInset then
			frame.RaidFrame.GroupsInset:StripTextures()
			frame.RaidFrame.GroupsInset:CreateBackdrop("Transparent")
		elseif frame.RaidFrame.ListInset then
			-- Fallback if ListInset exists
			frame.RaidFrame.ListInset:StripTextures()
			frame.RaidFrame.ListInset:CreateBackdrop("Transparent")
		end

		if frame.RaidFrame.ConvertToRaidButton then
			S:HandleButton(frame.RaidFrame.ConvertToRaidButton)
		end

		-- Point 8: Raid Info Button
		if frame.RaidFrame.ControlPanel and frame.RaidFrame.ControlPanel.RaidInfoButton then
			S:HandleButton(frame.RaidFrame.ControlPanel.RaidInfoButton)
		end

		if frame.RaidFrame.ControlPanel and frame.RaidFrame.ControlPanel.ReadyCheckButton then
			S:HandleButton(frame.RaidFrame.ControlPanel.ReadyCheckButton)
		end

		-- Skin EveryoneAssistCheckbox
		if frame.RaidFrame.ControlPanel and frame.RaidFrame.ControlPanel.EveryoneAssistCheckbox then
			S:HandleCheckBox(frame.RaidFrame.ControlPanel.EveryoneAssistCheckbox)
		end

		-- Skin RaidToolsButton
		if frame.RaidFrame.RaidToolsButton then
			S:HandleButton(frame.RaidFrame.RaidToolsButton)
		end
	end

	-- Hook Friends List (ScrollBox Items)
	BFL:DebugPrint("ElvUISkin: Hooking FriendsList")
	self:HookFriendsList(E, S)

	-- Skin Settings Frame
	BFL:DebugPrint("ElvUISkin: Skinning Settings")
	xpcall(function()
		self:SkinSettings(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning Settings: " .. tostring(err))
	end)

	-- Skin Changelog
	BFL:DebugPrint("ElvUISkin: Skinning Changelog")
	xpcall(function()
		self:SkinChangelog(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning Changelog: " .. tostring(err))
	end)

	-- Skin HelpFrame
	BFL:DebugPrint("ElvUISkin: Skinning HelpFrame")
	xpcall(function()
		self:SkinHelpFrame(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning HelpFrame: " .. tostring(err))
	end)

	-- Skin Export Frame
	BFL:DebugPrint("ElvUISkin: Skinning ExportFrame")
	xpcall(function()
		self:SkinExportFrame(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning ExportFrame: " .. tostring(err))
	end)

	-- Skin Import Frame
	BFL:DebugPrint("ElvUISkin: Skinning ImportFrame")
	xpcall(function()
		self:SkinImportFrame(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning ImportFrame: " .. tostring(err))
	end)

	-- Skin Note Cleanup Wizard
	BFL:DebugPrint("ElvUISkin: Skinning NoteCleanupWizard")
	xpcall(function()
		self:SkinNoteCleanupWizard(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning NoteCleanupWizard: " .. tostring(err))
	end)

	-- Skin Backup Viewer
	BFL:DebugPrint("ElvUISkin: Skinning BackupViewer")
	xpcall(function()
		self:SkinBackupViewer(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning BackupViewer: " .. tostring(err))
	end)

	-- Skin Search Builder (WHO frame)
	BFL:DebugPrint("ElvUISkin: Skinning SearchBuilder")
	xpcall(function()
		self:SkinSearchBuilder(E, S)
	end, function(err)
		BFL:DebugPrint("ElvUISkin: Error skinning SearchBuilder: " .. tostring(err))
	end)

	if not self.SearchBuilderHookInstalled then
		local WhoFrameModule = BFL:GetModule("WhoFrame")
		if WhoFrameModule and WhoFrameModule.ToggleSearchBuilder then
			hooksecurefunc(WhoFrameModule, "ToggleSearchBuilder", function()
				xpcall(function()
					self:SkinSearchBuilder(E, S)
				end, function(err)
					BFL:DebugPrint("ElvUISkin: Error skinning SearchBuilder hook: " .. tostring(err))
				end)
			end)
			hooksecurefunc(WhoFrameModule, "SetBuilderDocked", function()
				xpcall(function()
					self:SkinSearchBuilder(E, S)
				end, function(err)
					BFL:DebugPrint("ElvUISkin: Error skinning SearchBuilder (dock) hook: " .. tostring(err))
				end)
			end)
			self.SearchBuilderHookInstalled = true
		end
	end

	-- Hook RaidTools (lazy frame creation)
	if not self.RaidToolsHookInstalled then
		local RaidToolsModule = BFL:GetModule("RaidTools")
		if RaidToolsModule and RaidToolsModule.CreateFrame then
			hooksecurefunc(RaidToolsModule, "CreateFrame", function()
				xpcall(function()
					self:SkinRaidTools(E, S)
				end, function(err)
					BFL:DebugPrint("ElvUISkin: Error skinning RaidTools: " .. tostring(err))
				end)
			end)
			self.RaidToolsHookInstalled = true
		end
	end

	-- Apply FontFix after Skinning to ensure correct font sizes
	local FontFix = BFL:GetModule("FontFix")
	if FontFix then
		BFL:DebugPrint("ElvUISkin: Re-applying FontFix")
		FontFix:ApplyFixedFonts()
	end

	BFL:DebugPrint("ElvUI Skin applied to BetterFriendlist")
end

function ElvUISkin:HookFriendsList(E, S)
	local FriendsList = BFL:GetModule("FriendsList")
	if not FriendsList then
		return
	end

	-- Explicitly skin Classic ScrollBar if it exists now (Backup for initialization order)
	if BFL.IsClassic then
		local classicSB = _G["BetterFriendsClassicScrollFrameScrollBar"]
		if classicSB and not classicSB.isSkinned then
			SkinScrollBar(S, classicSB)
			classicSB.isSkinned = true
		end
	end

	-- Hook Group Header
	hooksecurefunc(FriendsList, "UpdateGroupHeaderButton", function(_, button, elementData)
		if not button.isSkinned then
			S:HandleButton(button)
			-- Strip the custom background texture if it exists
			if button.BG then
				button.BG:SetTexture(nil)
			end
			button.isSkinned = true
		end
	end)

	-- Hook Friend Button
	hooksecurefunc(FriendsList, "UpdateFriendButton", function(_, button, elementData)
		if not button.isSkinned then
			-- Don't full skin friend buttons as they are list items
			-- BFL: Travelpass button should NOT be skinned (User request)
			-- But we can skin the travel pass button in Retail only (not in Classic)
			-- if not BFL.IsClassic and button.travelPassButton then
			-- 	S:HandleButton(button.travelPassButton)
			-- 	-- Ensure icon remains visible and sized correctly
			-- 	if button.travelPassButton.NormalTexture then
			-- 		button.travelPassButton.NormalTexture:SetAlpha(1)
			-- 		button.travelPassButton.NormalTexture:SetSize(22, 22)
			-- 		button.travelPassButton.NormalTexture:SetPoint("CENTER")
			-- 	end
			-- end
			button.isSkinned = true
		end
	end)

	-- Hook Invite Header
	hooksecurefunc(FriendsList, "UpdateInviteHeaderButton", function(_, button, elementData)
		if not button.isSkinned then
			S:HandleButton(button)
			button.isSkinned = true
		end
	end)

	-- Hook Invite Button
	hooksecurefunc(FriendsList, "UpdateInviteButton", function(_, button, elementData)
		if not button.isSkinned then
			if button.AcceptButton then
				S:HandleButton(button.AcceptButton)
			end
			if button.DeclineButton then
				S:HandleButton(button.DeclineButton)
			end
			button.isSkinned = true
		end
	end)

	-- Hook UpdateSearchBoxState to enforce ElvUI positioning in Classic Normal Mode
	if FriendsList.UpdateSearchBoxState then
		hooksecurefunc(FriendsList, "UpdateSearchBoxState", function()
			if BFL.IsClassic then
				local DB = BFL:GetModule("DB")
				local simpleMode = DB and DB:Get("simpleMode", false)

				if not simpleMode then
					local frame = _G.BetterFriendsFrame
					if
						frame
						and frame.FriendsTabHeader
						and frame.FriendsTabHeader.SearchBox
						and frame.FriendsTabHeader.BattlenetFrame
					then
						local searchBox = frame.FriendsTabHeader.SearchBox
						searchBox:ClearAllPoints()
						searchBox:SetPoint("TOP", frame.FriendsTabHeader.BattlenetFrame, "BOTTOM", 0, -35)
						searchBox:SetPoint("LEFT", frame.Inset, "LEFT", 10, 0)
						searchBox:SetPoint("RIGHT", frame.Inset, "RIGHT", -10, 0)
					end
				end
			end
		end)
	end
end

function ElvUISkin:SkinRecruitAFriend(E, S, frame)
	local raf = frame.RecruitAFriendFrame
	if not raf then
		return
	end

	-- Skin Main Elements
	if raf.Border then
		raf.Border:StripTextures()
	end
	if raf.Background then
		raf.Background:Hide()
	end

	-- Skin Reward Claiming
	if raf.RewardClaiming then
		-- ElvUI Style: Handle Background
		if raf.RewardClaiming.Background then
			raf.RewardClaiming.Background:SetAlpha(0)
		end

		-- Hide Parchment Elements
		local parchmentElements = {
			"Bracket_TopLeft",
			"Bracket_TopRight",
			"Bracket_BottomLeft",
			"Bracket_BottomRight",
			"Watermark",
		}
		for _, name in ipairs(parchmentElements) do
			if raf.RewardClaiming[name] then
				raf.RewardClaiming[name]:Hide()
			end
		end

		-- Create Backdrop
		raf.RewardClaiming:CreateBackdrop("Transparent")

		-- Skin Claim/View Button
		if raf.RewardClaiming.ClaimOrViewRewardButton then
			S:HandleButton(raf.RewardClaiming.ClaimOrViewRewardButton)
		end

		if raf.RewardClaiming.Inset then
			raf.RewardClaiming.Inset:StripTextures()
			raf.RewardClaiming.Inset:CreateBackdrop("Transparent")
		end

		-- Next Reward Icon
		if raf.RewardClaiming.NextRewardButton then
			local button = raf.RewardClaiming.NextRewardButton
			-- CRITICAL: Do NOT strip textures, it removes the Icon!
			button:CreateBackdrop("Transparent")

			if button.Icon then
				button.Icon:SetTexCoord(unpack(E.TexCoords))
				button.Icon:SetParent(button.backdrop)
				button.Icon:SetInside()
				button.Icon:SetDrawLayer("ARTWORK")
			end

			if button.IconBorder then
				button.IconBorder:SetAlpha(0)
			end
			if button.IconOverlay then
				button.IconOverlay:SetAlpha(0)
			end
			if button.CircleMask then
				button.CircleMask:Hide()
			end
		end
	end

	-- Skin Recruit List
	if raf.RecruitList then
		if raf.RecruitList.ScrollFrameInset then
			raf.RecruitList.ScrollFrameInset:StripTextures()
			raf.RecruitList.ScrollFrameInset:CreateBackdrop("Transparent")
		end

		if raf.RecruitList.ScrollBar then
			SkinScrollBar(S, raf.RecruitList.ScrollBar)
		end

		-- Header
		if raf.RecruitList.Header then
			if raf.RecruitList.Header.Background then
				raf.RecruitList.Header.Background:Hide()
			end
			raf.RecruitList.Header:StripTextures()
			raf.RecruitList.Header:CreateBackdrop("Transparent")
		end
	end

	-- Skin Splash Frame
	if raf.SplashFrame then
		raf.SplashFrame:StripTextures()
		raf.SplashFrame:CreateBackdrop("Transparent")

		if raf.SplashFrame.Background then
			raf.SplashFrame.Background:Hide()
		end
		if raf.SplashFrame.PictureFrame then
			raf.SplashFrame.PictureFrame:Hide()
		end
		if raf.SplashFrame.Watermark then
			raf.SplashFrame.Watermark:Hide()
		end
		if raf.SplashFrame.Bracket_TopLeft then
			raf.SplashFrame.Bracket_TopLeft:Hide()
		end
		if raf.SplashFrame.Bracket_TopRight then
			raf.SplashFrame.Bracket_TopRight:Hide()
		end
		if raf.SplashFrame.Bracket_BottomLeft then
			raf.SplashFrame.Bracket_BottomLeft:Hide()
		end
		if raf.SplashFrame.Bracket_BottomRight then
			raf.SplashFrame.Bracket_BottomRight:Hide()
		end

		if raf.SplashFrame.Picture then
			raf.SplashFrame.Picture:SetInside() -- Make picture fill the frame or adjust as needed
			-- ElvUI does this, but maybe we want to keep it centered?
			-- Let's stick to ElvUI logic:
			-- SplashFrame.Picture:SetInside()
		end

		if raf.SplashFrame.OKButton then
			S:HandleButton(raf.SplashFrame.OKButton)
		end
	end
end

function ElvUISkin:SkinSettings(E, S)
	local frame = _G.BetterFriendlistSettingsFrame
	if not frame then
		return
	end

	S:HandlePortraitFrame(frame)

	-- Skin Tabs (Top) - Point 4: Adjust height
	for i = 1, 10 do
		local tab = _G["BetterFriendlistSettingsFrameTab" .. i]
		if tab then
			-- Fixed: Removed IsShown() check to ensure all tabs (including Beta/Global Sync)
			-- are skinned even if hidden during initial load.
			-- Tabs should exist if XML defines them.
			S:HandleTab(tab)
			tab:SetHeight(28) -- Fixed height
			HookBFLTabCenter(tab)
			CenterBFLTabText(tab)
		end
	end

	-- Skin Main Inset
	if frame.MainInset then
		frame.MainInset:StripTextures()
		frame.MainInset:CreateBackdrop("Transparent")
	end

	-- Skin ScrollBar
	if frame.ContentScrollFrame and frame.ContentScrollFrame.ScrollBar then
		S:HandleScrollBar(frame.ContentScrollFrame.ScrollBar)
	end

	-- Hook Refresh functions to skin EditBoxes (Point 3)
	local Settings = BFL:GetModule("Settings")
	if Settings then
		local function SkinEditBoxesInTab(tab)
			if not tab or not tab.components then
				return
			end
			for _, comp in ipairs(tab.components) do
				-- Check if it's an EditBox (or container with EditBox)
				if comp:IsObjectType("EditBox") then
					S:HandleEditBox(comp)
				elseif comp:IsObjectType("Frame") then
					-- Check children for EditBox (like nameFormatContainer)
					for _, child in ipairs({ comp:GetChildren() }) do
						if child:IsObjectType("EditBox") then
							S:HandleEditBox(child)
						end
					end
				end
			end
		end

		local function SkinFilterSortEditor()
			local editor = _G.BetterFriendlistFilterSortEditorFrame
			if not editor then
				return
			end

			if not editor.BFL_ElvFrameSkinned then
				S:HandlePortraitFrame(editor)
				if editor.Inset then
					editor.Inset:StripTextures()
					editor.Inset:CreateBackdrop("Transparent")
				end
				editor.BFL_ElvFrameSkinned = true
			end

			if editor.ScrollFrame then
				if editor.ScrollFrame.ScrollBar then
					SkinScrollBar(S, editor.ScrollFrame.ScrollBar)
				else
					for _, child in ipairs({ editor.ScrollFrame:GetChildren() }) do
						if child:IsObjectType("Slider") then
							S:HandleScrollBar(child)
						end
					end
				end
			end
		end

		-- Hook RefreshCategories to skin the new vertical buttons
		hooksecurefunc(Settings, "RefreshCategories", function()
			local frame = _G.BetterFriendlistSettingsFrame
			if frame and frame.CategoryList then
				-- Skin the Category List container
				if not frame.CategoryList.isSkinned then
					frame.CategoryList:StripTextures()
					frame.CategoryList:CreateBackdrop("Transparent")
					frame.CategoryList.isSkinned = true
				end

				-- Skin Buttons
				local children = { frame.CategoryList:GetChildren() }
				for _, child in ipairs(children) do
					if child:IsObjectType("Button") and not child.isSkinned then
						S:HandleButton(child)
						-- Remove default highlight/selected textures as ElvUI adds its own
						child:SetHighlightTexture("")

						-- Adjust text position if needed
						if child.text then
							child.text:ClearAllPoints()
							child.text:SetPoint("LEFT", child, "LEFT", 30, 0)
						end

						-- Hook OnClick or similar if necessary to update selected state visual
						-- But our SelectCategory logic handles text color, which is fine.

						child.isSkinned = true
					end
				end
			end
		end)

		hooksecurefunc(Settings, "RefreshGeneralTab", function()
			local content = frame.ContentScrollFrame.Content
			if content and content.GeneralTab then
				SkinEditBoxesInTab(content.GeneralTab)
			end
		end)
		hooksecurefunc(Settings, "EnsureFilterSortEditorPanel", SkinFilterSortEditor)
		hooksecurefunc(Settings, "RefreshFilterSortTab", SkinFilterSortEditor)

		-- Hook Global Sync Tab (Point 5: Skin dynamic headers and buttons)
		hooksecurefunc(Settings, "RefreshGlobalSyncTab", function()
			local content = frame.ContentScrollFrame.Content
			if content and content.GlobalSyncTab then
				local tab = content.GlobalSyncTab

				-- Skin Layout Headers (if they weren't caught by CreateHeader hook)
				-- We can iterate children to find unskinned buttons or headers
				local children = { tab:GetChildren() }
				for _, child in ipairs(children) do
					-- Case 1: Direct Button (unlikely in Global Sync, but possible)
					if child:IsObjectType("Button") and not child.isSkinned then
						-- Filter for the small action buttons (size 20x20 usually)
						local w, h = child:GetSize()
						if w < 30 and h < 30 then
							S:HandleButton(child)
							child.isSkinned = true
						end

					-- Case 2: Row Frame containing Button
					elseif child:IsObjectType("Frame") then
						-- Check children of the row for the action button
						local rowChildren = { child:GetChildren() }
						for _, btn in ipairs(rowChildren) do
							-- Skin Buttons (except Edit Note button which has a specific texture)
							if btn:IsObjectType("Button") and not btn.isSkinned then
								local w, h = btn:GetSize()
								if w < 30 and h < 30 then
									-- Check for Edit Note Icon
									local icon = btn:GetNormalTexture()
									local iconPath = icon and icon:GetTexture()
									local isEditNote = iconPath
										and (
											type(iconPath) == "string"
											and string.find(iconPath, "UI%-GuildButton%-PublicNote")
										)

									if not isEditNote then
										S:HandleButton(btn)
										btn.isSkinned = true
									end
								end
							end
						end
					end
				end
			end
		end)
	end

	-- Hook Components to skin dynamic elements
	if BFL.SettingsComponents then
		local C = BFL.SettingsComponents

		-- Checkbox
		if not C.IsSkinned then
			local oldCreateCheckbox = C.CreateCheckbox
			C.CreateCheckbox = function(...)
				local holder = oldCreateCheckbox(...)
				if holder and holder.checkBox then
					S:HandleCheckBox(holder.checkBox)
				end
				return holder
			end

			-- Double Checkbox
			local oldCreateDoubleCheckbox = C.CreateDoubleCheckbox
			C.CreateDoubleCheckbox = function(...)
				local holder = oldCreateDoubleCheckbox(...)
				if holder then
					if holder.LeftCheckbox then
						S:HandleCheckBox(holder.LeftCheckbox)
					end
					if holder.RightCheckbox then
						S:HandleCheckBox(holder.RightCheckbox)
					end
				end
				return holder
			end

			-- Slider
			local oldCreateSlider = C.CreateSlider
			C.CreateSlider = function(...)
				local holder = oldCreateSlider(...)
				if holder and holder.Slider then
					local slider = holder.Slider
					slider:StripTextures()
					slider:CreateBackdrop("Transparent")
					if slider.backdrop then
						slider.backdrop:SetPoint("TOPLEFT", 0, -5)
						slider.backdrop:SetPoint("BOTTOMRIGHT", 0, 5)
					end

					local thumb = slider:GetThumbTexture()
					if thumb then
						thumb:SetAlpha(0)
						if not slider.BFLThumb then
							local t = slider:CreateTexture(nil, "OVERLAY")
							t:SetTexture(E.Media.Textures.Melli or 130751)
							t:SetVertexColor(1, 0.82, 0)
							t:SetSize(10, 18)
							t:SetPoint("CENTER", thumb, "CENTER")
							slider.BFLThumb = t
						end
					end

					if slider.Back then
						S:HandleNextPrevButton(slider.Back, "left")
						slider.Back:SetSize(16, 16)
					end
					if slider.Forward then
						S:HandleNextPrevButton(slider.Forward, "right")
						slider.Forward:SetSize(16, 16)
					end
				end
				return holder
			end

			-- SliderWithColorPicker
			local oldCreateSliderColor = C.CreateSliderWithColorPicker
			C.CreateSliderWithColorPicker = function(...)
				local holder = oldCreateSliderColor(...)
				if holder and holder.Slider then
					-- Aggressive Skinning for MinimalSliderWithSteppersTemplate
					local slider = holder.Slider

					-- 1. Strip all textures (removes default Blizzard borders/track art)
					slider:StripTextures()

					-- 2. Create proper ElvUI Backdrop (The Track)
					slider:CreateBackdrop("Transparent")
					if slider.backdrop then
						slider.backdrop:SetPoint("TOPLEFT", 0, -5) -- Adjust height of track
						slider.backdrop:SetPoint("BOTTOMRIGHT", 0, 5)
					end

					-- 3. Handle Thumb
					local thumb = slider:GetThumbTexture()
					if thumb then
						thumb:SetAlpha(0) -- Hide default geometry

						if not slider.BFLThumb then
							local t = slider:CreateTexture(nil, "OVERLAY")
							t:SetTexture(E.Media.Textures.Melli or 130751)
							t:SetVertexColor(1, 0.82, 0)
							t:SetSize(10, 18)
							t:SetPoint("CENTER", thumb, "CENTER")
							slider.BFLThumb = t
						end
					end

					-- 4. Skin Stepper Buttons
					if slider.Back then
						S:HandleNextPrevButton(slider.Back, "left")
						slider.Back:SetSize(16, 16) -- Force size
					end
					if slider.Forward then
						S:HandleNextPrevButton(slider.Forward, "right")
						slider.Forward:SetSize(16, 16)
					end
				end
				return holder
			end

			-- Dropdown
			local oldCreateDropdown = C.CreateDropdown
			C.CreateDropdown = function(...)
				local holder = oldCreateDropdown(...)
				if holder and holder.DropDown then
					S:HandleDropDownBox(holder.DropDown)
				end
				return holder
			end

			-- Button
			local oldCreateButton = C.CreateButton
			C.CreateButton = function(...)
				local button = oldCreateButton(...)
				if button then
					S:HandleButton(button)
				end
				return button
			end

			-- List Item (Group Management)
			local oldCreateListItem = C.CreateListItem
			C.CreateListItem = function(...)
				local holder = oldCreateListItem(...)
				if holder then
					if holder.deleteButton then
						S:HandleButton(holder.deleteButton)
					end
					if holder.colorButton then
						S:HandleButton(holder.colorButton)
					end
					if holder.renameButton then
						S:HandleButton(holder.renameButton)
					end
					if holder.downButton then
						S:HandleButton(holder.downButton)
					end
					if holder.upButton then
						S:HandleButton(holder.upButton)
					end

					-- Skin the background if possible, or strip it
					if holder.bg then
						holder.bg:SetColorTexture(0, 0, 0, 0) -- Hide default bg
						holder:CreateBackdrop("Transparent")
					end
				end
				return holder
			end

			-- CheckboxDropdown (Favorite Icon row etc.)
			local oldCreateCheckboxDropdown = C.CreateCheckboxDropdown
			C.CreateCheckboxDropdown = function(...)
				local holder = oldCreateCheckboxDropdown(...)
				if holder then
					if holder.LeftCheckbox then
						S:HandleCheckBox(holder.LeftCheckbox)
					end
					if holder.RightDropdown then
						S:HandleDropDownBox(holder.RightDropdown)
					end
				end
				return holder
			end

			-- Input (Streamer Mode text field etc.)
			local oldCreateInput = C.CreateInput
			C.CreateInput = function(...)
				local holder = oldCreateInput(...)
				if holder and holder.Input then
					S:HandleEditBox(holder.Input)
				end
				return holder
			end

			-- ButtonRow (Reset buttons etc.)
			local oldCreateButtonRow = C.CreateButtonRow
			C.CreateButtonRow = function(...)
				local holder = oldCreateButtonRow(...)
				if holder then
					if holder.LeftButton then
						S:HandleButton(holder.LeftButton)
					end
					if holder.RightButton then
						S:HandleButton(holder.RightButton)
					end
				end
				return holder
			end

			C.IsSkinned = true
		end
	end
end

function ElvUISkin:SkinChangelog(E, S)
	local Changelog = BFL:GetModule("Changelog")
	if not Changelog then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistChangelogFrame
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Applying Skin to Changelog Window")
		S:HandlePortraitFrame(frame)

		-- Skin Main Inset
		if frame.MainInset then
			frame.MainInset:StripTextures()
			frame.MainInset:CreateBackdrop("Transparent")
		end

		-- Skin Buttons
		if frame.DiscordButton then
			S:HandleButton(frame.DiscordButton)
		end
		if frame.GitHubButton then
			S:HandleButton(frame.GitHubButton)
		end
		if frame.KoFiButton then
			S:HandleButton(frame.KoFiButton)
		end

		-- Skin ScrollBar
		if frame.ScrollBar then
			-- Retail
			SkinScrollBar(S, frame.ScrollBar)
		elseif frame.ScrollFrame then
			-- Classic or Fallback
			local children = { frame.ScrollFrame:GetChildren() }
			for _, child in ipairs(children) do
				if child:IsObjectType("Slider") then
					S:HandleScrollBar(child)
				end
			end
		end

		frame.isSkinned = true
	end

	hooksecurefunc(Changelog, "CreateChangelogWindow", Skin)
	Skin()
end

function ElvUISkin:SkinHelpFrame(E, S)
	local HelpFrame = BFL.HelpFrame or BFL:GetModule("HelpFrame")
	if not HelpFrame then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistHelpFrame
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Skinning HelpFrame")
		S:HandlePortraitFrame(frame)

		-- Skin Inset if it exists (ButtonFrameTemplate feature)
		if frame.Inset then
			frame.Inset:StripTextures()
			frame.Inset:CreateBackdrop("Transparent")
		end

		-- Skin ScrollBar
		if frame.ScrollBar then
			SkinScrollBar(S, frame.ScrollBar)
		elseif frame.ScrollFrame then
			-- Classic fallback or when using UIPanelScrollFrame
			if frame.ScrollFrame.ScrollBar then
				SkinScrollBar(S, frame.ScrollFrame.ScrollBar)
			elseif frame.ScrollFrame:GetName() then
				local scrollBar = _G[frame.ScrollFrame:GetName() .. "ScrollBar"]
				if scrollBar then
					SkinScrollBar(S, scrollBar)
				end
			end
		end

		frame.isSkinned = true
	end

	-- Hook creation
	hooksecurefunc(HelpFrame, "CreateFrame", Skin)
	-- Hook toggle as well just in case CreateFrame returns early but we missed skinning
	hooksecurefunc(HelpFrame, "Toggle", Skin)

	-- Try to skin immediately if it exists
	if _G.BetterFriendlistHelpFrame then
		Skin()
	end
end

-- Helper: Skin all UIPanelButtonTemplate / GameMenuButtonTemplate buttons in a frame
local function SkinChildButtons(S, parent)
	for _, child in ipairs({ parent:GetChildren() }) do
		if child:IsObjectType("Button") and not child.isSkinned then
			-- Skip close buttons (handled by HandlePortraitFrame)
			local name = child:GetName()
			if not name or not string.find(name, "CloseButton") then
				S:HandleButton(child)
				child.isSkinned = true
			end
		end
	end
end

-- Helper: Skin ScrollBar from UIPanelScrollFrameTemplate (legacy Slider-based)
-- UIPanelScrollFrameTemplate creates a classic Slider scrollbar, NOT a modern ScrollBar.
-- We must use S:HandleScrollBar() (for Slider), NOT SkinScrollBar/HandleTrimScrollBar.
local function SkinUIPanelScrollBar(S, scrollFrame)
	if not scrollFrame then
		return
	end
	-- Try direct ScrollBar child (some frames store it)
	if scrollFrame.ScrollBar then
		if scrollFrame.ScrollBar:IsObjectType("Slider") then
			pcall(S.HandleScrollBar, S, scrollFrame.ScrollBar)
		else
			pcall(SkinScrollBar, S, scrollFrame.ScrollBar)
		end
		return
	end
	-- Try named ScrollBar (UIPanelScrollFrameTemplate convention: $parentScrollBar)
	local name = scrollFrame:GetName()
	if name then
		local scrollBar = _G[name .. "ScrollBar"]
		if scrollBar then
			pcall(S.HandleScrollBar, S, scrollBar)
			return
		end
	end
	-- Fallback: find Slider child among all children
	for _, child in ipairs({ scrollFrame:GetChildren() }) do
		if child:IsObjectType("Slider") then
			pcall(S.HandleScrollBar, S, child)
			return
		end
	end
end

function ElvUISkin:SkinExportFrame(E, S)
	local Settings = BFL:GetModule("Settings")
	if not Settings then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistExportFrame
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Applying Skin to Export Frame")

		-- BasicFrameTemplateWithInset
		frame:StripTextures()
		frame:CreateBackdrop("Transparent")

		-- Close Button
		if frame.CloseButton then
			S:HandleCloseButton(frame.CloseButton)
		end

		-- Inset
		if frame.InsetFrame then
			frame.InsetFrame:StripTextures()
		end

		-- ScrollFrame & ScrollBar
		if frame.scrollFrame then
			SkinUIPanelScrollBar(S, frame.scrollFrame)
		end

		-- Skin all buttons (Copy All)
		SkinChildButtons(S, frame)

		frame.isSkinned = true
	end

	-- Hook creation
	hooksecurefunc(Settings, "CreateExportFrame", Skin)

	-- Try to skin immediately if it exists
	if _G.BetterFriendlistExportFrame then
		Skin()
	end
end

function ElvUISkin:SkinImportFrame(E, S)
	local Settings = BFL:GetModule("Settings")
	if not Settings then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistImportFrame
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Applying Skin to Import Frame")

		-- BasicFrameTemplateWithInset
		frame:StripTextures()
		frame:CreateBackdrop("Transparent")

		-- Close Button
		if frame.CloseButton then
			S:HandleCloseButton(frame.CloseButton)
		end

		-- Inset
		if frame.InsetFrame then
			frame.InsetFrame:StripTextures()
		end

		-- ScrollFrame & ScrollBar
		if frame.scrollFrame then
			SkinUIPanelScrollBar(S, frame.scrollFrame)
		end

		-- Skin all buttons (Import, Cancel)
		SkinChildButtons(S, frame)

		frame.isSkinned = true
	end

	-- Hook creation
	hooksecurefunc(Settings, "CreateImportFrame", Skin)

	-- Try to skin immediately if it exists
	if _G.BetterFriendlistImportFrame then
		Skin()
	end
end

function ElvUISkin:SkinNoteCleanupWizard(E, S)
	local NoteCleanupWizard = BFL.NoteCleanupWizard
	if not NoteCleanupWizard then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistNoteCleanupWizard
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Applying Skin to Note Cleanup Wizard")

		-- ButtonFrameTemplate
		S:HandlePortraitFrame(frame)

		-- Inset
		if frame.Inset then
			frame.Inset:StripTextures()
			frame.Inset:CreateBackdrop("Transparent")
		end

		-- ScrollFrame & ScrollBar
		if frame.scrollFrame then
			SkinUIPanelScrollBar(S, frame.scrollFrame)
		end

		-- Skin buttons and search boxes in all child frames (topBar children)
		for _, child in ipairs({ frame:GetChildren() }) do
			-- Skin buttons inside sub-frames (topBar)
			if child:IsObjectType("Frame") and not child:IsObjectType("Button") then
				for _, subChild in ipairs({ child:GetChildren() }) do
					if subChild:IsObjectType("Button") and not subChild.isSkinned then
						S:HandleButton(subChild)
						subChild.isSkinned = true
					end
					if subChild:IsObjectType("EditBox") and not subChild.isSkinned then
						S:HandleEditBox(subChild)
						subChild.isSkinned = true
					end
				end
			end
		end

		frame.isSkinned = true
	end

	-- Hook creation
	hooksecurefunc(NoteCleanupWizard, "CreateWizardFrame", Skin)

	-- Also hook Show in case frame was already created
	hooksecurefunc(NoteCleanupWizard, "Show", Skin)

	-- Try to skin immediately if it exists
	if _G.BetterFriendlistNoteCleanupWizard then
		Skin()
	end
end

function ElvUISkin:SkinBackupViewer(E, S)
	local NoteCleanupWizard = BFL.NoteCleanupWizard
	if not NoteCleanupWizard then
		return
	end

	local function Skin()
		local frame = _G.BetterFriendlistNoteBackupViewer
		if not frame or frame.isSkinned then
			return
		end

		BFL:DebugPrint("ElvUISkin: Applying Skin to Backup Viewer")

		-- ButtonFrameTemplate
		S:HandlePortraitFrame(frame)

		-- Inset
		if frame.Inset then
			frame.Inset:StripTextures()
			frame.Inset:CreateBackdrop("Transparent")
		end

		-- ScrollFrame & ScrollBar
		if frame.scrollFrame then
			SkinUIPanelScrollBar(S, frame.scrollFrame)
		end

		-- Skin buttons and search boxes in all child frames (topBar children)
		for _, child in ipairs({ frame:GetChildren() }) do
			-- Skin buttons inside sub-frames (topBar)
			if child:IsObjectType("Frame") and not child:IsObjectType("Button") then
				for _, subChild in ipairs({ child:GetChildren() }) do
					if subChild:IsObjectType("Button") and not subChild.isSkinned then
						S:HandleButton(subChild)
						subChild.isSkinned = true
					end
					if subChild:IsObjectType("EditBox") and not subChild.isSkinned then
						S:HandleEditBox(subChild)
						subChild.isSkinned = true
					end
				end
			end
		end

		frame.isSkinned = true
	end

	-- Hook creation
	hooksecurefunc(NoteCleanupWizard, "CreateBackupViewerFrame", Skin)

	-- Also hook ShowBackupViewer in case frame was already created
	hooksecurefunc(NoteCleanupWizard, "ShowBackupViewer", Skin)

	-- Try to skin immediately if it exists
	if _G.BetterFriendlistNoteBackupViewer then
		Skin()
	end
end

function ElvUISkin:SkinSearchBuilder(E, S)
	local WhoFrameModule = BFL:GetModule("WhoFrame")
	if not WhoFrameModule then
		return
	end

	local flyout = WhoFrameModule.builderFlyout
	if not flyout then
		return
	end

	-- Apply ElvUI backdrop
	flyout:StripTextures()
	flyout:CreateBackdrop("Transparent")

	-- Skin builder inputs and dropdowns
	local builder = WhoFrameModule.builder
	if builder then
		if builder.nameInput then
			S:HandleEditBox(builder.nameInput)
		end
		if builder.guildInput then
			S:HandleEditBox(builder.guildInput)
		end
		if builder.zoneInput then
			S:HandleEditBox(builder.zoneInput)
		end
		if builder.levelMin then
			S:HandleEditBox(builder.levelMin)
		end
		if builder.levelMax then
			S:HandleEditBox(builder.levelMax)
		end
		local isDocked = WhoFrameModule.builderDocked
		if builder.classDropdown then
			pcall(S.HandleDropDownBox, S, builder.classDropdown)
			if BFL.IsClassic then
				FixClassicDropdownHitbox(builder.classDropdown, isDocked and 105 or 115, 24)
				if not builder.classDropdown.BFL_OrigXOfs then
					local p, rel, rp, x, y = builder.classDropdown:GetPoint(1)
					builder.classDropdown.BFL_OrigXOfs = x or 0
					builder.classDropdown.BFL_OrigYOfs = y or 0
				end
				local p, rel, rp = builder.classDropdown:GetPoint(1)
				if p then
					builder.classDropdown:SetPoint(
						p,
						rel,
						rp,
						builder.classDropdown.BFL_OrigXOfs + 10,
						builder.classDropdown.BFL_OrigYOfs
					)
				end
			elseif BFL.HasModernDropdown then
				if not builder.classDropdown.BFL_OrigXOfs then
					local p, rel, rp, x, y = builder.classDropdown:GetPoint(1)
					builder.classDropdown.BFL_OrigXOfs = x or 0
					builder.classDropdown.BFL_OrigYOfs = y or 0
				end
				local p, rel, rp = builder.classDropdown:GetPoint(1)
				if p then
					builder.classDropdown:SetPoint(
						p,
						rel,
						rp,
						builder.classDropdown.BFL_OrigXOfs + 1,
						builder.classDropdown.BFL_OrigYOfs
					)
				end
			end
		end
		if builder.raceDropdown then
			pcall(S.HandleDropDownBox, S, builder.raceDropdown)
			if BFL.IsClassic then
				FixClassicDropdownHitbox(builder.raceDropdown, isDocked and 105 or 115, 24)
				if not builder.raceDropdown.BFL_OrigXOfs then
					local p, rel, rp, x, y = builder.raceDropdown:GetPoint(1)
					builder.raceDropdown.BFL_OrigXOfs = x or 0
					builder.raceDropdown.BFL_OrigYOfs = y or 0
				end
				local p, rel, rp = builder.raceDropdown:GetPoint(1)
				if p then
					builder.raceDropdown:SetPoint(
						p,
						rel,
						rp,
						builder.raceDropdown.BFL_OrigXOfs + 10,
						builder.raceDropdown.BFL_OrigYOfs
					)
				end
			elseif BFL.HasModernDropdown then
				if not builder.raceDropdown.BFL_OrigXOfs then
					local p, rel, rp, x, y = builder.raceDropdown:GetPoint(1)
					builder.raceDropdown.BFL_OrigXOfs = x or 0
					builder.raceDropdown.BFL_OrigYOfs = y or 0
				end
				local p, rel, rp = builder.raceDropdown:GetPoint(1)
				if p then
					builder.raceDropdown:SetPoint(
						p,
						rel,
						rp,
						builder.raceDropdown.BFL_OrigXOfs + 1,
						builder.raceDropdown.BFL_OrigYOfs
					)
				end
			end
		end
	end

	-- Skin child buttons (close, search, reset)
	local dockBtn = WhoFrameModule.builderDockBtn
	for _, child in ipairs({ flyout:GetChildren() }) do
		if child:IsObjectType("Button") and not child.isSkinned then
			if child == dockBtn then
				-- Dock button uses a custom icon texture, don't skin it
				child.isSkinned = true
			else
				local w = child:GetWidth()
				if w <= 24 then
					pcall(S.HandleCloseButton, S, child)
				else
					S:HandleButton(child)
				end
				child.isSkinned = true
			end
		end
	end

	-- Skin docked container if it exists
	local container = WhoFrameModule.builderDockedContainer
	if container and not container.isSkinned then
		pcall(function()
			S:HandlePortraitFrame(container)
		end)
		container.isSkinned = true
	end
end

-- ============================================================================
-- RaidTools Skinning
-- ============================================================================

function ElvUISkin:SkinRaidTools(E, S)
	local frame = _G.BetterFriendlistRaidToolsFrame
	if not frame then
		return
	end

	-- Frame backdrop
	pcall(S.HandlePortraitFrame, S, frame)

	-- Close button
	if frame.CloseButton then
		pcall(S.HandleCloseButton, S, frame.CloseButton)
	end

	-- Dropdowns
	local sortDropdown = _G["BFLRaidToolsSortMode"]
	if sortDropdown then
		pcall(S.HandleDropDownBox, S, sortDropdown)
		if BFL.IsClassic then
			FixClassicDropdownHitbox(sortDropdown, 189, 24)
			if not sortDropdown.BFL_OrigXOfs then
				local p, rel, rp, x, y = sortDropdown:GetPoint(1)
				sortDropdown.BFL_OrigXOfs = x or 0
				sortDropdown.BFL_OrigYOfs = y or 0
			end
			local p, rel, rp = sortDropdown:GetPoint(1)
			if p then
				sortDropdown:SetPoint(p, rel, rp, sortDropdown.BFL_OrigXOfs + 16, sortDropdown.BFL_OrigYOfs)
			end
		end
		if BFL.IsRetail then
			sortDropdown:SetWidth(240)
		end
	end

	local preserveDropdown = _G["BFLRaidToolsPreserveGroups"]
	if preserveDropdown then
		pcall(S.HandleDropDownBox, S, preserveDropdown)
		if BFL.IsClassic then
			FixClassicDropdownHitbox(preserveDropdown, 189, 24)
			if not preserveDropdown.BFL_OrigXOfs then
				local p, rel, rp, x, y = preserveDropdown:GetPoint(1)
				preserveDropdown.BFL_OrigXOfs = x or 0
				preserveDropdown.BFL_OrigYOfs = y or 0
			end
			local p, rel, rp = preserveDropdown:GetPoint(1)
			if p then
				preserveDropdown:SetPoint(p, rel, rp, preserveDropdown.BFL_OrigXOfs + 16, preserveDropdown.BFL_OrigYOfs)
			end
		end
		if BFL.IsRetail then
			preserveDropdown:SetWidth(240)
		end
	end

	-- Checkboxes
	local balanceDps = _G["BFLRaidToolsBalanceDps"]
	if balanceDps then
		S:HandleCheckBox(balanceDps)
		if BFL.IsRetail then
			local p, rel, rp, x, y = balanceDps:GetPoint(1)
			if p then
				balanceDps:SetPoint(p, rel, rp, x - 3, y)
			end
		end
	end

	local resumeCheck = _G["BFLRaidToolsResumeCheck"]
	if resumeCheck then
		S:HandleCheckBox(resumeCheck)
		if BFL.IsRetail then
			local p, rel, rp, x, y = resumeCheck:GetPoint(1)
			if p then
				resumeCheck:SetPoint(p, rel, rp, x - 3, y)
			end
		end
	end

	-- Buttons
	if frame.sortButton then
		S:HandleButton(frame.sortButton)
	end
	if frame.splitButton then
		S:HandleButton(frame.splitButton)
	end
	if frame.splitOddsButton then
		S:HandleButton(frame.splitOddsButton)
	end
	if frame.promoteButton then
		S:HandleButton(frame.promoteButton)
	end

	-- RETAIL FINETUNING: Additional Retail-specific tweaks for RaidTools here
	if BFL.IsRetail then
	end

	-- CLASSIC FINETUNING: Additional Classic-specific tweaks for RaidTools here
	if BFL.IsClassic then
	end
end
