-- VEX GMod Internal - Pure Lua Cheat Script

VEX = VEX or {}
VEX.AimToggleState = VEX.AimToggleState or false
VEX.SilentAimToggleState = VEX.SilentAimToggleState or false

VEX.Config = VEX.Config or {}
local defaults = {
    aim_enabled = false,
    aim_key = MOUSE_RIGHT,
    aim_mode = 1, -- 1 = Hold, 2 = Toggle, 3 = Always On
    aim_fov = 15,
    aim_bone = "ValveBiped.Bip01_Head1",
    aim_silent = false,
    aim_silent_fov = 25,
    aim_silent_key = 0,
    aim_silent_mode = 3, -- 1 = Hold, 2 = Toggle, 3 = Always On
    aim_norecoil = false,
    aim_nospread = false,
    aim_tracers = false,
    aim_tracers_color = Color(140, 90, 240),
    aim_bubblesound = false,
    aim_glass_hitmarker = true,
    misc_namechanger = false,
    misc_namechanger_target = "VEX User",

    esp_enabled = false,
    esp_boxes = false,
    esp_names = false,
    esp_health = false,
    esp_skeleton = false,
    esp_weapon = false,
    esp_box_type = 1,
    esp_box_color = Color(255, 255, 255),
    esp_name_color = Color(255, 255, 255),
    esp_health_style = 1,
    esp_health_color = Color(0, 255, 0),
    esp_skeleton_color = Color(255, 255, 255),
    esp_weapon_color = Color(255, 255, 255),
    esp_offscreen = false,
    esp_offscreen_style = 1,
    esp_offscreen_size = 15,
    esp_offscreen_color = Color(220, 0, 255),
    esp_ignore_team = false,
    esp_ignore_friends = false,
    esp_ignore_sleepers = false,
    esp_ignore_npcs = false,
    esp_show_team = false,
    esp_show_friends = false,
    esp_outline3d = false,

    move_bhop = false,
    move_strafe = false,

    vis_fov = 110,
    vis_wfov = 110,
    vis_vm_x = 0,
    vis_vm_y = 0,
    vis_vm_z = 0,
    vis_thirdperson = false,
    vis_thirdperson_dist = 100,
    vis_freecam = false,

    chams_enabled = false,
    chams_players = false,
    chams_self = false,
    chams_weapon = false,
    chams_type = 1, -- 1=Wireframe, 2=Flat, 3=Metallic, 4=Glow, 5=Glass
    chams_players_type = 1,
    chams_self_type = 1,
    chams_weapon_type = 1,
    chams_rgb = false,
    chams_player_color = Color(255, 0, 255),
    chams_self_color = Color(0, 255, 255),
    chams_weapon_color = Color(255, 255, 0),
    vis_menu_font = "Consolas",
    vis_menu_fontsize = 13,
}

function VEX.UpdateMenuFont()
    local family = VEX.Config.vis_menu_font or "Consolas"
    local size = VEX.Config.vis_menu_fontsize or 13
    surface.CreateFont("VEX_Menu_Normal", {
        font = family,
        size = size,
        weight = 500,
        antialias = true
    })
    surface.CreateFont("VEX_Menu_Bold", {
        font = family,
        size = size,
        weight = 800,
        antialias = true
    })
    surface.CreateFont("VEX_Menu_Large", {
        font = family,
        size = size + 6,
        weight = 800,
        antialias = true
    })
    surface.CreateFont("VEX_Menu_Icon", {
        font = "Segoe UI",
        size = 22,
        weight = 500,
        antialias = true
    })
    surface.CreateFont("VEX_Preview_ESP", {
        font = family,
        size = 32,
        weight = 800,
        antialias = true
    })
end

VEX.UpdateMenuFont()

for k, v in pairs(defaults) do
    if VEX.Config[k] == nil then
        VEX.Config[k] = v
    end
end


VEX.IsCapturing = VEX.IsCapturing or false
VEX.OriginalCapture = VEX.OriginalCapture or render.Capture
VEX.OriginalReadPixels = VEX.OriginalReadPixels or render.ReadPixels
VEX.OriginalCapturePixels = VEX.OriginalCapturePixels or render.CapturePixels
VEX.OriginalJpeg = VEX.OriginalJpeg or concommand.GetTable()["jpeg"]
VEX.OriginalScreenshot = VEX.OriginalScreenshot or concommand.GetTable()["screenshot"]
VEX.OriginalViewModelFOV = 54

function VEX.SetCapturing(state)
    VEX.IsCapturing = state
    local ply = LocalPlayer()
    if IsValid(ply) then
        local wep = ply:GetActiveWeapon()
        if IsValid(wep) then
            local targetFov = state and 54 or VEX.Config.vis_wfov
            wep.ViewModelFOV = targetFov
            if wep.SetViewModelFOV then
                pcall(function() wep:SetViewModelFOV(targetFov) end)
            end
        end
    end
    local vm_cvar = GetConVar("viewmodel_fov")
    if vm_cvar then
        pcall(function()
            local targetFov = state and 54 or VEX.Config.vis_wfov
            if vm_cvar:GetInt() ~= targetFov then
                RunConsoleCommand("viewmodel_fov", tostring(targetFov))
            end
        end)
    end
end

VEX.OriginalHookCall = VEX.OriginalHookCall or hook.Call
hook.Call = function(name, gm, ...)
    if VEX.IsCapturing then
        if name == "CalcView" then
            local ply, pos, angles, fov = ...
            if IsValid(ply) then
                local view = {}
                view.origin = ply:EyePos()
                view.angles = ply:EyeAngles()
                
                -- Get GMod's default FOV desired value
                local fovCvar = GetConVar("fov_desired")
                local defaultFov = fovCvar and fovCvar:GetInt() or 90
                view.fov = defaultFov
                view.vm_fov = 54
                view.drawviewer = false
                return view
            end
        elseif name == "CalcViewModelView" then
            local wep, vm, old_pos, old_ang, pos, ang = ...
            if IsValid(wep) then
                wep.ViewModelFOV = 54
                if wep.SetViewModelFOV then
                    pcall(function() wep:SetViewModelFOV(54) end)
                end
            end
            -- Return the original engine pos/ang without any custom offsets
            return old_pos, old_ang
        elseif name == "PreDrawViewModel" then
            -- Run original hooks first
            local success, res = pcall(VEX.OriginalHookCall, name, gm, ...)
            local vm, ply, wep = ...
            if IsValid(wep) then
                wep.ViewModelFOV = 54
                if wep.SetViewModelFOV then
                    pcall(function() wep:SetViewModelFOV(54) end)
                end
            end
            if success then
                return res
            end
            return
        end
    end
    return VEX.OriginalHookCall(name, gm, ...)
end

-- ConVar Metatable Detours to override viewmodel_fov for custom weapon bases (TFA, ArcCW, etc.)
local cvMeta = FindMetaTable("ConVar")
if cvMeta then
    VEX.OriginalCVGetInt = VEX.OriginalCVGetInt or cvMeta.GetInt
    VEX.OriginalCVGetFloat = VEX.OriginalCVGetFloat or cvMeta.GetFloat
    VEX.OriginalCVGetString = VEX.OriginalCVGetString or cvMeta.GetString
    VEX.OriginalCVGetBool = VEX.OriginalCVGetBool or cvMeta.GetBool

    cvMeta.GetInt = function(self)
        local name = self:GetName()
        if name == "viewmodel_fov" then
            return VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov
        end
        return VEX.OriginalCVGetInt(self)
    end

    cvMeta.GetFloat = function(self)
        local name = self:GetName()
        if name == "viewmodel_fov" then
            return VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov
        end
        return VEX.OriginalCVGetFloat(self)
    end

    cvMeta.GetString = function(self)
        local name = self:GetName()
        if name == "viewmodel_fov" then
            return tostring(VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov)
        end
        return VEX.OriginalCVGetString(self)
    end

    cvMeta.GetBool = function(self)
        local name = self:GetName()
        if name == "viewmodel_fov" then
            return (VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov) ~= 0
        end
        return VEX.OriginalCVGetBool(self)
    end
end

VEX.OriginalGetConVarNumber = VEX.OriginalGetConVarNumber or GetConVarNumber
VEX.OriginalGetConVarString = VEX.OriginalGetConVarString or GetConVarString

function GetConVarNumber(name)
    if name == "viewmodel_fov" then
        return VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov
    end
    return VEX.OriginalGetConVarNumber(name)
end

function GetConVarString(name)
    if name == "viewmodel_fov" then
        return tostring(VEX.IsCapturing and (VEX.OriginalViewModelFOV or 54) or VEX.Config.vis_wfov)
    end
    return VEX.OriginalGetConVarString(name)
end

VEX.CapturePreviewRequested = VEX.CapturePreviewRequested or false
VEX.CapturePreviewType = VEX.CapturePreviewType or ""

-- Intercepted screenshot preview GUI
function VEX.ShowScreenshotPreview(filename, captureType)
    -- Play warning bell sound
    surface.PlaySound("ambient/alarms/warningbell1.wav")
    
    -- Close any existing VEX preview frames
    if IsValid(VEX.PreviewFrame) then
        VEX.PreviewFrame:Remove()
    end
    
    -- Create a clean, compact notification panel (DFrame)
    local frame = vgui.Create("DFrame")
    VEX.PreviewFrame = frame
    frame:SetSize(285, 215)
    frame:SetPos(15, 15) -- Top-left corner
    frame:SetTitle("")
    frame:ShowCloseButton(false)
    frame:SetDraggable(false)
    frame:SetSizable(false)
    
    -- Smooth fade-in animation & Auto-close timer
    frame:SetAlpha(0)
    frame:AlphaTo(255, 0.3, 0)
    
    timer.Create("VEX_PreviewNotification_Close", 6, 1, function()
        if IsValid(frame) then
            frame:AlphaTo(0, 0.5, 0, function()
                if IsValid(frame) then frame:Remove() end
            end)
        end
    end)
    
    frame.Paint = function(self, w, h)
        -- Premium dark theme with purple neon border
        draw.RoundedBox(6, 0, 0, w, h, Color(15, 15, 20, 240))
        draw.RoundedBoxEx(6, 0, 0, w, 24, Color(140, 90, 240, 255), true, true, false, false)
        surface.SetDrawColor(140, 90, 240, 150)
        surface.DrawOutlinedRect(0, 0, w, h, 1)
        
        draw.SimpleText("VEX SECURITY - SCREENSHOT BLOCKED", "DermaDefaultBold", 10, 5, Color(255, 255, 255))
    end
    
    -- Label showing capture source
    local lbl = frame:Add("DLabel")
    lbl:SetText("Clean capture sent to " .. (captureType or "Server"))
    lbl:SetTextColor(Color(0, 255, 120))
    lbl:Dock(TOP)
    lbl:DockMargin(10, 4, 10, 4)
    lbl:SetFont("DermaDefault")
    lbl:SetContentAlignment(5)
    
    -- Embedded preview image panel
    local imgPanel = frame:Add("DPanel")
    imgPanel:Dock(FILL)
    imgPanel:DockMargin(10, 0, 10, 10)
    imgPanel.Paint = function(self, w, h)
        surface.SetDrawColor(25, 25, 30, 255)
        surface.DrawRect(0, 0, w, h)
        surface.SetDrawColor(140, 90, 240, 50)
        surface.DrawOutlinedRect(0, 0, w, h, 1)
    end
    
    local img = imgPanel:Add("DImage")
    img:Dock(FILL)
    img:DockMargin(3, 3, 3, 3)
    img:SetImage("data/" .. filename)
end

-- Apply screengrab detours to capture clean frames
render.Capture = function(data)
    VEX.SetCapturing(true)
    
    local menuVisible = false
    if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
        menuVisible = true
        VEX.MenuFrame:SetVisible(false)
    end
    local previewVisible = false
    if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
        previewVisible = true
        VEX.PreviewFrame:SetVisible(false)
    end
    
    local ply = LocalPlayer()
    if IsValid(ply) then
        render.Clear(0, 0, 0, 255, true, true)
        local view = {
            origin = ply:EyePos(),
            angles = ply:EyeAngles(),
            x = 0,
            y = 0,
            w = ScrW(),
            h = ScrH(),
            fov = ply:GetFOV(),
            vm_fov = VEX.OriginalViewModelFOV,
            dopostprocess = true,
            drawhud = true,
            drawmonitors = true,
            drawviewmodel = true
        }
        render.RenderView(view)
    end
    
    -- Capture the full clean screen (entire screen without menu/ESP/chams) for the warning preview
    local previewData = VEX.OriginalCapture({format = "jpeg", quality = 70, x = 0, y = 0, w = ScrW(), h = ScrH()})

    local success, captureData = pcall(VEX.OriginalCapture, data)
    
    if menuVisible and IsValid(VEX.MenuFrame) then
        VEX.MenuFrame:SetVisible(true)
    end
    if previewVisible and IsValid(VEX.PreviewFrame) then
        VEX.PreviewFrame:SetVisible(true)
    end
    
    VEX.SetCapturing(false)
    
    if success and captureData then
        if previewData then
            local ext = (data and data.format == "png") and "png" or "jpg"
            local filename = "vex_screengrab_" .. tostring(os.time()) .. "_" .. math.random(100, 999) .. "." .. ext
            file.Write(filename, previewData)
            timer.Simple(0.1, function()
                VEX.ShowScreenshotPreview(filename, "render.Capture Request")
            end)
        end
        return captureData
    else
        return nil
    end
end

render.ReadPixels = function(x, y, w, h, format, dst)
    VEX.SetCapturing(true)
    
    local menuVisible = false
    if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
        menuVisible = true
        VEX.MenuFrame:SetVisible(false)
    end
    local previewVisible = false
    if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
        previewVisible = true
        VEX.PreviewFrame:SetVisible(false)
    end
    
    local ply = LocalPlayer()
    if IsValid(ply) then
        render.Clear(0, 0, 0, 255, true, true)
        local view = {
            origin = ply:EyePos(),
            angles = ply:EyeAngles(),
            x = 0,
            y = 0,
            w = ScrW(),
            h = ScrH(),
            fov = ply:GetFOV(),
            vm_fov = VEX.OriginalViewModelFOV,
            dopostprocess = true,
            drawhud = true,
            drawmonitors = true,
            drawviewmodel = true
        }
        render.RenderView(view)
    end
    
    -- Capture the full clean screen (entire screen without menu/ESP/chams) for the warning preview
    local previewData = VEX.OriginalCapture({format = "jpeg", quality = 70, x = 0, y = 0, w = ScrW(), h = ScrH()})

    local success, pixels = pcall(VEX.OriginalReadPixels, x, y, w, h, format, dst)
    
    if menuVisible and IsValid(VEX.MenuFrame) then
        VEX.MenuFrame:SetVisible(true)
    end
    if previewVisible and IsValid(VEX.PreviewFrame) then
        VEX.PreviewFrame:SetVisible(true)
    end
    
    VEX.SetCapturing(false)

    if previewData then
        local filename = "vex_screengrab_" .. tostring(os.time()) .. "_" .. math.random(100, 999) .. ".jpg"
        file.Write(filename, previewData)
        timer.Simple(0.1, function()
            VEX.ShowScreenshotPreview(filename, "render.ReadPixels Request")
        end)
    end
    
    if success then
        return pixels
    else
        return nil
    end
end

render.CapturePixels = function()
    VEX.SetCapturing(true)
    
    local menuVisible = false
    if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
        menuVisible = true
        VEX.MenuFrame:SetVisible(false)
    end
    local previewVisible = false
    if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
        previewVisible = true
        VEX.PreviewFrame:SetVisible(false)
    end
    
    local ply = LocalPlayer()
    if IsValid(ply) then
        render.Clear(0, 0, 0, 255, true, true)
        local view = {
            origin = ply:EyePos(),
            angles = ply:EyeAngles(),
            x = 0,
            y = 0,
            w = ScrW(),
            h = ScrH(),
            fov = ply:GetFOV(),
            vm_fov = VEX.OriginalViewModelFOV,
            dopostprocess = true,
            drawhud = true,
            drawmonitors = true,
            drawviewmodel = true
        }
        render.RenderView(view)
    end
    
    -- Capture the full clean screen (entire screen without menu/ESP/chams) for the warning preview
    local previewData = VEX.OriginalCapture({format = "jpeg", quality = 70, x = 0, y = 0, w = ScrW(), h = ScrH()})

    local success, res = pcall(VEX.OriginalCapturePixels)
    
    if menuVisible and IsValid(VEX.MenuFrame) then
        VEX.MenuFrame:SetVisible(true)
    end
    if previewVisible and IsValid(VEX.PreviewFrame) then
        VEX.PreviewFrame:SetVisible(true)
    end
    
    VEX.SetCapturing(false)

    if previewData then
        local filename = "vex_screengrab_" .. tostring(os.time()) .. "_" .. math.random(100, 999) .. ".jpg"
        file.Write(filename, previewData)
        timer.Simple(0.1, function()
            VEX.ShowScreenshotPreview(filename, "render.CapturePixels Request")
        end)
    end
    
    if success then
        return res
    else
        return nil
    end
end

local concommands = concommand.GetTable()
if concommands["jpeg"] then
    local oldJpeg = concommands["jpeg"]
    concommand.Add("jpeg", function(ply, cmd, args, argStr)
        VEX.SetCapturing(true)
        
        local menuVisible = false
        if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
            menuVisible = true
            VEX.MenuFrame:SetVisible(false)
        end
        local previewVisible = false
        if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
            previewVisible = true
            VEX.PreviewFrame:SetVisible(false)
        end

        VEX.CapturePreviewRequested = true
        VEX.CapturePreviewType = "jpeg Console Command (F5)"
        
        if VEX.OriginalJpeg then
            VEX.OriginalJpeg(ply, cmd, args, argStr)
        end
        
        timer.Create("VEX_JpegRestore", 0.5, 1, function()
            VEX.SetCapturing(false)
            if menuVisible and IsValid(VEX.MenuFrame) then
                VEX.MenuFrame:SetVisible(true)
            end
            if previewVisible and IsValid(VEX.PreviewFrame) then
                VEX.PreviewFrame:SetVisible(true)
            end
        end)
    end)
end

if concommands["screenshot"] then
    local oldScreenshot = concommand.GetTable()["screenshot"]
    concommand.Add("screenshot", function(ply, cmd, args, argStr)
        VEX.SetCapturing(true)
        
        local menuVisible = false
        if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
            menuVisible = true
            VEX.MenuFrame:SetVisible(false)
        end
        local previewVisible = false
        if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
            previewVisible = true
            VEX.PreviewFrame:SetVisible(false)
        end

        VEX.CapturePreviewRequested = true
        VEX.CapturePreviewType = "screenshot Console Command"
        
        if VEX.OriginalScreenshot then
            VEX.OriginalScreenshot(ply, cmd, args, argStr)
        end
        
        timer.Create("VEX_ScreenshotRestore", 0.5, 1, function()
            VEX.SetCapturing(false)
            if menuVisible and IsValid(VEX.MenuFrame) then
                VEX.MenuFrame:SetVisible(true)
            end
            if previewVisible and IsValid(VEX.PreviewFrame) then
                VEX.PreviewFrame:SetVisible(true)
            end
        end)
    end)
end

VEX.SpectateTarget = nil

-- Helper for Rainbow/RGB Color
function VEX.GetRainbowColor()
    local t = RealTime() * 1.5 -- speed of rainbow cycle
    local r = math.sin(t) * 127 + 128
    local g = math.sin(t + 2.09439) * 127 + 128 -- 2*pi/3 phase offset
    local b = math.sin(t + 4.18879) * 127 + 128 -- 4*pi/3 phase offset
    return Color(r, g, b)
end

local function GetKeyNameFriendly(key, mode)
    if mode == 3 then return "ALWAYS ON" end
    local modeText = " [HOLD]"
    if mode == 2 then modeText = " [TOGGLE]" end

    if not key or key == 0 then return "NONE" .. modeText end
    local name = input.GetKeyName(key)
    if name then
        return string.upper(name) .. modeText
    end
    if key == MOUSE_LEFT then return "MOUSE1" .. modeText end
    if key == MOUSE_RIGHT then return "MOUSE2" .. modeText end
    if key == MOUSE_MIDDLE then return "MOUSE3" .. modeText end
    if key == MOUSE_4 then return "MOUSE4" .. modeText end
    if key == MOUSE_5 then return "MOUSE5" .. modeText end
    return "KEY_" .. tostring(key) .. modeText
end

local function IsAimKeyPressed()
    local mode = VEX.Config.aim_mode or 1
    if mode == 3 then return true end -- Always On
    if mode == 2 then return VEX.AimToggleState end -- Toggle

    local key = VEX.Config.aim_key
    if not key or key == 0 then return false end
    if key >= 107 and key <= 112 then
        return input.IsMouseDown(key)
    else
        return input.IsKeyDown(key)
    end
end

local function IsSilentAimKeyPressed()
    local mode = VEX.Config.aim_silent_mode or 3
    if mode == 3 then return true end -- Always On
    if mode == 2 then return VEX.SilentAimToggleState end -- Toggle

    local key = VEX.Config.aim_silent_key
    if not key or key == 0 then return true end
    if key >= 107 and key <= 112 then
        return input.IsMouseDown(key)
    else
        return input.IsKeyDown(key)
    end
end

-- Restore detours on script reload to prevent infinite recursion
if VEX.OriginalHookCall then hook.Call = VEX.OriginalHookCall end
if VEX.OriginalCapture then render.Capture = VEX.OriginalCapture end
if VEX.OriginalReadPixels then render.ReadPixels = VEX.OriginalReadPixels end
if VEX.OriginalCapturePixels then render.CapturePixels = VEX.OriginalCapturePixels end
if VEX.OriginalJpeg then concommand.Add("jpeg", VEX.OriginalJpeg) end
if VEX.OriginalScreenshot then concommand.Add("screenshot", VEX.OriginalScreenshot) end

local cvMeta = FindMetaTable("ConVar")
if cvMeta then
    if VEX.OriginalCVGetInt then cvMeta.GetInt = VEX.OriginalCVGetInt end
    if VEX.OriginalCVGetFloat then cvMeta.GetFloat = VEX.OriginalCVGetFloat end
    if VEX.OriginalCVGetString then cvMeta.GetString = VEX.OriginalCVGetString end
    if VEX.OriginalCVGetBool then cvMeta.GetBool = VEX.OriginalCVGetBool end
end
if VEX.OriginalGetConVarNumber then GetConVarNumber = VEX.OriginalGetConVarNumber end
if VEX.OriginalGetConVarString then GetConVarString = VEX.OriginalGetConVarString end
hook.Remove("Think", "VEX_ScreenshotKeyDetector")
hook.Remove("Think", "SteamScreenshotMonitor")
hook.Remove("Think", "VEX_WeaponDetourManager")

-- Clean up existing hooks if re-executing
local hook_names = {"HUDPaint", "CreateMove", "CalcView", "RenderScreenspaceEffects", "PreDrawViewModel", "PostDrawViewModel", "PreDrawPlayerHands", "PostDrawPlayerHands", "PrePlayerDraw", "PostPlayerDraw", "EntityFireBullets", "PostRender"}
for _, h in ipairs(hook_names) do
    hook.Remove(h, "VEX_ESP")
    hook.Remove(h, "VEX_AIM")
    hook.Remove(h, "VEX_MOVE")
    hook.Remove(h, "VEX_VIEW")
    hook.Remove(h, "VEX_CHAMS")
    hook.Remove(h, "VEX_PlayerChams")
    hook.Remove(h, "VEX_PlayerChams_P")
    hook.Remove(h, "VEX_VM")
    hook.Remove(h, "VEX_VM_P")
    hook.Remove(h, "VEX_HANDS")
    hook.Remove(h, "VEX_HANDS_P")
    hook.Remove(h, "VEX_SPREAD")
    hook.Remove(h, "VEX_TRACERS")
    hook.Remove(h, "VEX_PreviewCapturer")

    hook.Remove(h, "PaintHUD_Base")
    hook.Remove(h, "PhysicsUpdate")
    hook.Remove(h, "CreateMovePrediction")
    hook.Remove(h, "CalcViewOverride")
    hook.Remove(h, "RenderScreenspaceEffectsOverride")
    hook.Remove(h, "DrawModelChams")
    hook.Remove(h, "DrawModelChams_P")
    hook.Remove(h, "DrawVM")
    hook.Remove(h, "DrawVM_P")
    hook.Remove(h, "DrawHands")
    hook.Remove(h, "DrawHands_P")
    hook.Remove(h, "SpreadOverride")
    hook.Remove(h, "RenderTracers")
    hook.Remove(h, "CaptureCleanFrame")
end
hook.Remove("EntityEmitSound", "VEX_BubbleSounds")
hook.Remove("EntityEmitSound", "BubbleSounds")
hook.Remove("Think", "VEX_KeyBind")
hook.Remove("Think", "VEX_SilentKeyBind")
hook.Remove("Think", "VEX_KeyModeTracker")
hook.Remove("Think", "AimbotKeyTracker")
hook.Remove("Think", "VEX_KeyBind_Capture")
hook.Remove("Think", "VEX_SilentKeyBind_Capture")

local aimKeyWasPressed = false
local silentKeyWasPressed = false

local lastScreenshotTime = 0
hook.Add("Think", "SteamScreenshotMonitor", function()
    -- Detect PrintScreen, Steam Screenshot (default F12) or F5 Screenshot keys
    if input.IsKeyDown(KEY_F12) or input.IsKeyDown(KEY_PRINTSCREEN) or input.IsKeyDown(KEY_F5) then
        local now = RealTime()
        if now - lastScreenshotTime > 1.0 then
            lastScreenshotTime = now
            
            VEX.SetCapturing(true)
            
            local menuVisible = false
            if IsValid(VEX.MenuFrame) and VEX.MenuFrame:IsVisible() then
                menuVisible = true
                VEX.MenuFrame:SetVisible(false)
            end
            local previewVisible = false
            if IsValid(VEX.PreviewFrame) and VEX.PreviewFrame:IsVisible() then
                previewVisible = true
                VEX.PreviewFrame:SetVisible(false)
            end

            VEX.CapturePreviewRequested = true
            VEX.CapturePreviewType = "Steam / PrintScreen / F5 Screenshot"
            
            notification.AddLegacy("Screenshot key detected! Capturing cleanly...", NOTIFY_GENERIC, 4)
            
            timer.Create("VEX_SteamScreenshotRestore", 0.5, 1, function()
                VEX.SetCapturing(false)
                if menuVisible and IsValid(VEX.MenuFrame) then
                    VEX.MenuFrame:SetVisible(true)
                end
                if previewVisible and IsValid(VEX.PreviewFrame) then
                    VEX.PreviewFrame:SetVisible(true)
                end
            end)
        end
    end
end)

local lastWep = nil
hook.Add("Think", "VEX_WeaponDetourManager", function()
    local ply = LocalPlayer()
    if not IsValid(ply) then return end

    local wep = ply:GetActiveWeapon()
    if not IsValid(wep) then 
        lastWep = nil
        return 
    end

    if wep ~= lastWep then
        lastWep = wep
        
        -- Detour CalcViewModelView on the active weapon instance
        if wep.CalcViewModelView and not wep.VEX_OriginalCalcViewModelView then
            wep.VEX_OriginalCalcViewModelView = wep.CalcViewModelView
            wep.CalcViewModelView = function(self, vm, old_pos, old_ang, pos, ang)
                local targetFov = VEX.IsCapturing and 54 or VEX.Config.vis_wfov
                self.ViewModelFOV = targetFov
                if self.SetViewModelFOV then
                    pcall(function() self:SetViewModelFOV(targetFov) end)
                end

                local rPos, rAng = self:VEX_OriginalCalcViewModelView(vm, old_pos, old_ang, pos, ang)
                rPos = rPos or pos
                rAng = rAng or ang
                
                if VEX.IsCapturing then
                    return old_pos, old_ang -- strip offsets during capture
                end
                return rPos, rAng
            end
        end

        -- Detour PreDrawViewModel on the active weapon instance
        if wep.PreDrawViewModel and not wep.VEX_OriginalPreDrawViewModel then
            wep.VEX_OriginalPreDrawViewModel = wep.PreDrawViewModel
            wep.PreDrawViewModel = function(self, vm)
                local targetFov = VEX.IsCapturing and 54 or VEX.Config.vis_wfov
                self.ViewModelFOV = targetFov
                if self.SetViewModelFOV then
                    pcall(function() self:SetViewModelFOV(targetFov) end)
                end
                local res = self:VEX_OriginalPreDrawViewModel(vm)
                return res
            end
        end

        -- Detour DrawViewModel on the active weapon instance
        if wep.DrawViewModel and not wep.VEX_OriginalDrawViewModel then
            wep.VEX_OriginalDrawViewModel = wep.DrawViewModel
            wep.DrawViewModel = function(self, vm)
                local targetFov = VEX.IsCapturing and 54 or VEX.Config.vis_wfov
                self.ViewModelFOV = targetFov
                if self.SetViewModelFOV then
                    pcall(function() self:SetViewModelFOV(targetFov) end)
                end
                local res = self:VEX_OriginalDrawViewModel(vm)
                return res
            end
        end

        -- Detour GetViewModelFOV on the active weapon instance
        if not wep.VEX_OriginalGetViewModelFOV then
            wep.VEX_OriginalGetViewModelFOV = wep.GetViewModelFOV or function(self) return self.ViewModelFOV or 54 end
            wep.GetViewModelFOV = function(self)
                if VEX.IsCapturing then
                    return 54
                end
                return VEX.Config.vis_wfov
            end
        end
    end

    -- Constantly enforce the FOV during normal play and capture
    if IsValid(wep) then
        local targetFov = VEX.IsCapturing and 54 or VEX.Config.vis_wfov
        wep.ViewModelFOV = targetFov
        if wep.SetViewModelFOV then
            pcall(function() wep:SetViewModelFOV(targetFov) end)
        end
    end
end)

hook.Add("Think", "AimbotKeyTracker", function()
    -- Regular Aimbot Toggle
    if VEX.Config.aim_mode == 2 then
        local pressed = false
        local key = VEX.Config.aim_key
        if key and key > 0 then
            if key >= 107 and key <= 112 then
                pressed = input.IsMouseDown(key)
            else
                pressed = input.IsKeyDown(key)
            end
        end
        if pressed and not aimKeyWasPressed then
            VEX.AimToggleState = not VEX.AimToggleState
            surface.PlaySound("buttons/lightswitch2.wav")
        end
        aimKeyWasPressed = pressed
    else
        VEX.AimToggleState = false
    end

    -- Silent Aimbot Toggle
    if VEX.Config.aim_silent_mode == 2 then
        local pressed = false
        local key = VEX.Config.aim_silent_key
        if key and key > 0 then
            if key >= 107 and key <= 112 then
                pressed = input.IsMouseDown(key)
            else
                pressed = input.IsKeyDown(key)
            end
        end
        if pressed and not silentKeyWasPressed then
            VEX.SilentAimToggleState = not VEX.SilentAimToggleState
            surface.PlaySound("buttons/lightswitch2.wav")
        end
        silentKeyWasPressed = pressed
    else
        VEX.SilentAimToggleState = false
    end
end)
hook.Remove("Think", "VEX_SilentKeyBind")

-- ============================================
-- Materials creation for Chams
-- ============================================
local suffix = tostring(math.random(100000, 999999))
local chams_materials = {
    [1] = CreateMaterial("VEX_Mat_Wire_" .. suffix, "VertexLitGeneric", { ["$wireframe"] = 1, ["$ignorez"] = 1, ["$nofog"] = 1, ["$model"] = 1 }),
    [2] = CreateMaterial("VEX_Mat_Flat_" .. suffix, "UnlitGeneric", { ["$basetexture"] = "color/white", ["$ignorez"] = 1, ["$nofog"] = 1, ["$model"] = 1 }),
    [3] = CreateMaterial("VEX_Mat_Metal_" .. suffix, "VertexLitGeneric", {
        ["$basetexture"] = "models/debug/debugwhite",
        ["$bumpmap"] = "models/debug/debugwhite",
        ["$envmap"] = "env_cubemap",
        ["$envmaptint"] = "[0.8 0.8 0.8]",
        ["$envmapcontrast"] = 1,
        ["$phong"] = 1,
        ["$phongexponent"] = 30,
        ["$phongboost"] = 8,
        ["$phongfresnelranges"] = "[0.2 0.5 1]",
        ["$halflambert"] = 1,
        ["$ignorez"] = 1,
        ["$nofog"] = 1,
        ["$model"] = 1
    }),
    [4] = CreateMaterial("VEX_Mat_Glow_" .. suffix, "VertexLitGeneric", { ["$basetexture"] = "color/white", ["$ignorez"] = 1, ["$additive"] = 1, ["$nofog"] = 1, ["$model"] = 1 }),
    [5] = CreateMaterial("VEX_Mat_Glass_" .. suffix, "VertexLitGeneric", { ["$basetexture"] = "color/white", ["$ignorez"] = 1, ["$additive"] = 1, ["$translucent"] = 1, ["$model"] = 1 }),
}

-- ============================================
-- ESP Rendering (HUDPaint)
-- ============================================
local function DrawBox(x, y, w, h, col)
    surface.SetDrawColor(col)
    surface.DrawOutlinedRect(x, y, w, h, 1)
    surface.SetDrawColor(0, 0, 0, 200)
    surface.DrawOutlinedRect(x - 1, y - 1, w + 2, h + 2, 1)
    surface.DrawOutlinedRect(x + 1, y + 1, w - 2, h - 2, 1)
end

local function DrawCornerBox(x, y, w, h, col)
    local len = math.min(w, h) * 0.25
    surface.SetDrawColor(col)
    -- Top-Left
    surface.DrawRect(x, y, len, 1)
    surface.DrawRect(x, y, 1, len)
    -- Top-Right
    surface.DrawRect(x + w - len, y, len, 1)
    surface.DrawRect(x + w, y, 1, len)
    -- Bottom-Left
    surface.DrawRect(x, y + h, len, 1)
    surface.DrawRect(x, y + h - len, 1, len)
    -- Bottom-Right
    surface.DrawRect(x + w - len, y + h, len, 1)
    surface.DrawRect(x + w, y + h - len, 1, len)

    -- Black outlines for corners
    surface.SetDrawColor(0, 0, 0, 200)
    -- Top-Left
    surface.DrawRect(x - 1, y - 1, len + 2, 1)
    surface.DrawRect(x - 1, y - 1, 1, len + 2)
    -- Top-Right
    surface.DrawRect(x + w - len - 1, y - 1, len + 2, 1)
    surface.DrawRect(x + w + 1, y - 1, 1, len + 2)
    -- Bottom-Left
    surface.DrawRect(x - 1, y + h + 1, len + 2, 1)
    surface.DrawRect(x - 1, y + h - len - 1, 1, len + 2)
    -- Bottom-Right
    surface.DrawRect(x + w - len - 1, y + h + 1, len + 2, 1)
    surface.DrawRect(x + w + 1, y + h - len - 1, 1, len + 2)
end

local function Draw3DBox(ent, col)
    if not IsValid(ent) then return end
    local min, max = ent:OBBMins(), ent:OBBMaxs()
    local corners = {
        ent:LocalToWorld(Vector(min.x, min.y, min.z)):ToScreen(),
        ent:LocalToWorld(Vector(min.x, min.y, max.z)):ToScreen(),
        ent:LocalToWorld(Vector(min.x, max.y, min.z)):ToScreen(),
        ent:LocalToWorld(Vector(min.x, max.y, max.z)):ToScreen(),
        ent:LocalToWorld(Vector(max.x, min.y, min.z)):ToScreen(),
        ent:LocalToWorld(Vector(max.x, min.y, max.z)):ToScreen(),
        ent:LocalToWorld(Vector(max.x, max.y, min.z)):ToScreen(),
        ent:LocalToWorld(Vector(max.x, max.y, max.z)):ToScreen()
    }
    
    local edges = {
        {1, 5}, {2, 6}, {3, 7}, {4, 8},
        {1, 3}, {2, 4}, {5, 7}, {6, 8},
        {1, 2}, {3, 4}, {5, 6}, {7, 8}
    }
    
    -- Outlines first
    surface.SetDrawColor(0, 0, 0, 200)
    for _, edge in ipairs(edges) do
        local p1 = corners[edge[1]]
        local p2 = corners[edge[2]]
        if p1.visible and p2.visible then
            surface.DrawLine(p1.x - 1, p1.y, p2.x - 1, p2.y)
            surface.DrawLine(p1.x + 1, p1.y, p2.x + 1, p2.y)
            surface.DrawLine(p1.x, p1.y - 1, p2.x, p2.y - 1)
            surface.DrawLine(p1.x, p1.y + 1, p2.x, p2.y + 1)
        end
    end
    
    -- Main lines
    surface.SetDrawColor(col)
    for _, edge in ipairs(edges) do
        local p1 = corners[edge[1]]
        local p2 = corners[edge[2]]
        if p1.visible and p2.visible then
            surface.DrawLine(p1.x, p1.y, p2.x, p2.y)
        end
    end
end

local function GetSkeletonBones(ent)
    local skeleton = {
        { "ValveBiped.Bip01_Head1", "ValveBiped.Bip01_Neck1" },
        { "ValveBiped.Bip01_Neck1", "ValveBiped.Bip01_Spine4" },
        { "ValveBiped.Bip01_Spine4", "ValveBiped.Bip01_Spine2" },
        { "ValveBiped.Bip01_Spine2", "ValveBiped.Bip01_Spine" },
        { "ValveBiped.Bip01_Spine", "ValveBiped.Bip01_Pelvis" },
        
        -- Left Arm
        { "ValveBiped.Bip01_Spine4", "ValveBiped.Bip01_L_Clavicle" },
        { "ValveBiped.Bip01_L_Clavicle", "ValveBiped.Bip01_L_UpperArm" },
        { "ValveBiped.Bip01_L_UpperArm", "ValveBiped.Bip01_L_Forearm" },
        { "ValveBiped.Bip01_L_Forearm", "ValveBiped.Bip01_L_Hand" },
        
        -- Right Arm
        { "ValveBiped.Bip01_Spine4", "ValveBiped.Bip01_R_Clavicle" },
        { "ValveBiped.Bip01_R_Clavicle", "ValveBiped.Bip01_R_UpperArm" },
        { "ValveBiped.Bip01_R_UpperArm", "ValveBiped.Bip01_R_Forearm" },
        { "ValveBiped.Bip01_R_Forearm", "ValveBiped.Bip01_R_Hand" },
        
        -- Left Leg
        { "ValveBiped.Bip01_Pelvis", "ValveBiped.Bip01_L_Thigh" },
        { "ValveBiped.Bip01_L_Thigh", "ValveBiped.Bip01_L_Calf" },
        { "ValveBiped.Bip01_L_Calf", "ValveBiped.Bip01_L_Foot" },
        
        -- Right Leg
        { "ValveBiped.Bip01_Pelvis", "ValveBiped.Bip01_R_Thigh" },
        { "ValveBiped.Bip01_R_Thigh", "ValveBiped.Bip01_R_Calf" },
        { "ValveBiped.Bip01_R_Calf", "ValveBiped.Bip01_R_Foot" }
    }
    return skeleton
end

local function Project3DTo2D(modelPanel, point3D, W, H)
    if not IsValid(modelPanel) then return nil end
    local C = modelPanel.vCamPos or Vector(90, 0, 36)
    local L = modelPanel.vLookatPos or Vector(0, 0, 36)
    local fov = modelPanel.fFOV or 50
    
    -- In DModelPanel, the camera is looking from CamPos to LookAt
    local ang = (L - C):Angle()
    local F = ang:Forward()
    local R = -ang:Right() -- DModelPanel right vector is negated relative to standard world space coordinate projections
    local U = ang:Up()
    
    local v = point3D - C
    local d_forward = v:Dot(F)
    local d_right = v:Dot(R)
    local d_up = v:Dot(U)
    
    if d_forward <= 0 then return nil end
    
    -- Compute projected coords using trigonometry
    local frustum_h = 2 * d_forward * math.tan(math.rad(fov / 2))
    local frustum_w = frustum_h * (W / H)
    
    local screenX = W / 2 + (d_right / frustum_w) * W
    local screenY = H / 2 - (d_up / frustum_h) * H
    
    return screenX, screenY
end

local function GetEntityBonePosition(ent, boneName, isPreview)
    local boneIdx = ent:LookupBone(boneName)
    if not boneIdx then return nil end
    
    if isPreview then
        ent:SetupBones()
        local matrix = ent:GetBoneMatrix(boneIdx)
        if matrix then
            return matrix:GetTranslation()
        end
    end
    
    local pos, ang = ent:GetBonePosition(boneIdx)
    return pos
end

local function DrawEntityESP(ent, isPreview, modelPanel, w, h)
    if not isPreview and not VEX.Config.esp_enabled then return end
    if not IsValid(ent) then return end
    
    local boxX, boxY, boxW, boxH
    local bones2D = {}
    
    if isPreview then
        -- Project OBB corners to find a dynamic wrapping 2D bounding box
        local min, max = ent:OBBMins(), ent:OBBMaxs()
        local corners = {
            Vector(min.x, min.y, min.z),
            Vector(min.x, min.y, max.z),
            Vector(min.x, max.y, min.z),
            Vector(min.x, max.y, max.z),
            Vector(max.x, min.y, min.z),
            Vector(max.x, min.y, max.z),
            Vector(max.x, max.y, min.z),
            Vector(max.x, max.y, max.z)
        }
        
        local minX, minY, maxX, maxY = w, h, 0, 0
        local validCorners = 0
        
        for _, corner in ipairs(corners) do
            local worldCorner = ent:LocalToWorld(corner)
            local sx, sy = Project3DTo2D(modelPanel, worldCorner, w, h)
            if sx and sy then
                minX = math.min(minX, sx)
                minY = math.min(minY, sy)
                maxX = math.max(maxX, sx)
                maxY = math.max(maxY, sy)
                validCorners = validCorners + 1
            end
        end
        
        if validCorners == 8 then
            boxX = minX - 2
            boxY = minY - 2
            boxW = (maxX - minX) + 4
            boxH = (maxY - minY) + 4
        else
            boxX = w / 2 - 50
            boxY = h / 2 - 110
            boxW = 100
            boxH = 220
        end
    else
        -- In-game player box estimation
        local pos = ent:GetPos()
        local headPos = GetEntityBonePosition(ent, "ValveBiped.Bip01_Head1", false)
        if not headPos then headPos = pos + Vector(0, 0, 72) end
        
        local screenPos = pos:ToScreen()
        local screenHeadPos = (headPos + Vector(0, 0, 8)):ToScreen()
        
        if not screenPos.visible or not screenHeadPos.visible then
            return -- Offscreen indicator is handled by the main HUDPaint loop
        end
        
        boxH = math.abs(screenPos.y - screenHeadPos.y)
        boxW = boxH / 2
        boxX = screenPos.x - boxW / 2
        boxY = screenHeadPos.y
        
        -- Bones
        if VEX.Config.esp_skeleton then
            local bones = GetSkeletonBones(ent)
            for _, pair in ipairs(bones) do
                local p1 = GetEntityBonePosition(ent, pair[1], false)
                local p2 = GetEntityBonePosition(ent, pair[2], false)
                if p1 and p2 then
                    local s1 = p1:ToScreen()
                    local s2 = p2:ToScreen()
                    if s1.visible and s2.visible then
                        table.insert(bones2D, { p1 = s1, p2 = s2 })
                    end
                end
            end
        end
    end
    
    local teamColor = Color(255, 255, 255)
    if isPreview then
        local lp = LocalPlayer()
        if IsValid(lp) then
            teamColor = team.GetColor(lp:Team()) or Color(255, 255, 255)
        end
    else
        if ent.Team and ent:IsPlayer() then
            teamColor = team.GetColor(ent:Team()) or Color(255, 255, 255)
        end
    end
    
    -- 1. Bounding Box
    if VEX.Config.esp_boxes and not isPreview then
        local boxColor = VEX.Config.esp_box_color or teamColor
        if VEX.Config.esp_box_type == 2 then
            DrawCornerBox(boxX, boxY, boxW, boxH, boxColor)
        elseif VEX.Config.esp_box_type == 3 then
            Draw3DBox(ent, boxColor)
        else
            DrawBox(boxX, boxY, boxW, boxH, boxColor)
        end
    end
    
    -- 2. Skeleton
    if VEX.Config.esp_skeleton and not isPreview then
        local skeletonColor = VEX.Config.esp_skeleton_color or Color(255, 255, 255, 220)
        surface.SetDrawColor(skeletonColor)
        for _, pair in ipairs(bones2D) do
            surface.DrawLine(pair.p1.x, pair.p1.y, pair.p2.x, pair.p2.y)
        end
    end
    
    -- 3. Name
    if VEX.Config.esp_names then
        local nameColor = VEX.Config.esp_name_color or Color(255, 255, 255)
        local nameText = "Player"
        if isPreview then
            local lp = LocalPlayer()
            if IsValid(lp) then nameText = lp:Nick() end
        else
            if ent.Nick then nameText = ent:Nick() end
        end
        draw.SimpleText(nameText, "DermaDefault", boxX + boxW/2, boxY - 15, nameColor, TEXT_ALIGN_CENTER)
    end
    
    -- 4. Health Bar
    if VEX.Config.esp_health then
        local hp = 100
        local maxHp = 100
        if not isPreview then
            hp = math.Clamp(ent:Health() or 0, 0, ent:GetMaxHealth() or 100)
            maxHp = ent:GetMaxHealth() or 100
        end
        local hpPercent = hp / maxHp
        local hpColor = VEX.Config.esp_health_color or Color((1 - hpPercent) * 255, hpPercent * 255, 0)
        
        if VEX.Config.esp_health_style == 2 then -- Text style
            draw.SimpleText(tostring(hp) .. " HP", "DermaDefault", boxX - 8, boxY + boxH/2, hpColor, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
        else -- Bar style
            local barH = boxH * hpPercent
            surface.SetDrawColor(0, 0, 0, 150)
            surface.DrawRect(boxX - 6, boxY, 4, boxH)
            surface.SetDrawColor(hpColor)
            surface.DrawRect(boxX - 5, boxY + (boxH - barH), 2, barH)
        end
    end
    
    -- 5. Weapon Text
    if VEX.Config.esp_weapon then
        local wep = nil
        if isPreview then
            local lp = LocalPlayer()
            if IsValid(lp) then wep = lp:GetActiveWeapon() end
        else
            if IsValid(ent) and ent.GetActiveWeapon and ent:IsPlayer() then 
                wep = ent:GetActiveWeapon() 
            end
        end
        
        if IsValid(wep) then
            local wepName = wep:GetPrintName() or wep:GetClass() or "None"
            local weaponColor = VEX.Config.esp_weapon_color or Color(220, 220, 220)
            draw.SimpleText(wepName, "DermaDefault", boxX + boxW/2, boxY + boxH + 2, weaponColor, TEXT_ALIGN_CENTER)
        end
    end
end

hook.Add("HUDPaint", "PaintHUD_Base", function()
    if VEX.IsCapturing then return end

    -- Draw FOV circles automatically based on enabled states
    local ply = LocalPlayer()
    if IsValid(ply) then
        local fov = ply:GetFOV()
        if fov and fov > 0 then
            local cx, cy = ScrW() / 2, ScrH() / 2
            local steps = 64

            -- Normal Aimbot FOV
            if VEX.Config.aim_enabled then
                local rad = math.tan(math.rad(VEX.Config.aim_fov) / 2) / math.tan(math.rad(fov) / 2) * (ScrW() / 2)
                surface.SetDrawColor(255, 255, 255, 80)
                local px, py = cx + rad, cy
                for i = 1, steps do
                    local angle = math.rad(i * (360 / steps))
                    local x = cx + math.cos(angle) * rad
                    local y = cy + math.sin(angle) * rad
                    surface.DrawLine(px, py, x, y)
                    px, py = x, y
                end
            end

            -- Silent Aimbot FOV
            if VEX.Config.aim_silent then
                local sRad = math.tan(math.rad(VEX.Config.aim_silent_fov) / 2) / math.tan(math.rad(fov) / 2) * (ScrW() / 2)
                surface.SetDrawColor(140, 90, 240, 100) -- Accent purple
                local spx, spy = cx + sRad, cy
                for i = 1, steps do
                    local angle = math.rad(i * (360 / steps))
                    local x = cx + math.cos(angle) * sRad
                    local y = cy + math.sin(angle) * sRad
                    surface.DrawLine(spx, spy, x, y)
                    spx, spy = x, y
                end
            end
        end
    end

    if not VEX.Config.esp_enabled then return end

    local localPlayer = LocalPlayer()
    for _, ply in ipairs(player.GetAll()) do
        if not IsValid(ply) or not ply:Alive() or ply == localPlayer or ply:IsDormant() then continue end

        -- Ignores
        if VEX.Config.esp_ignore_team and ply:Team() == localPlayer:Team() then continue end
        if VEX.Config.esp_ignore_friends and ply:GetFriendStatus() == "friend" then continue end
        if VEX.Config.esp_ignore_sleepers and ply:GetNWBool("IsSleeping") then continue end
        if VEX.Config.esp_ignore_npcs and (not ply:IsPlayer()) then continue end

        -- Show filters
        if VEX.Config.esp_show_friends and ply:GetFriendStatus() ~= "friend" then continue end

        local pos = ply:GetPos()
        local headPos = ply:GetBonePosition(ply:LookupBone("ValveBiped.Bip01_Head1") or 0)
        if not headPos then headPos = pos + Vector(0, 0, 72) end

        local screenPos = pos:ToScreen()
        local screenHeadPos = (headPos + Vector(0, 0, 8)):ToScreen()

        if not screenPos.visible or not screenHeadPos.visible then
            if VEX.Config.esp_offscreen then
                -- Draw offscreen indicator pointing to player
                local plyPos = pos
                local localPos = localPlayer:GetPos()
                local eyeAngles = localPlayer:EyeAngles()
                
                local dir = (plyPos - localPlayer:EyePos()):GetNormalized()
                local forward = eyeAngles:Forward()
                local right = eyeAngles:Right()
                
                local dotForward = dir:Dot(forward)
                local dotRight = dir:Dot(right)
                
                local angle = math.atan2(dotRight, dotForward)
                
                local cx, cy = ScrW() / 2, ScrH() / 2
                local radius = 100 -- Distance from center of screen
                local indicatorSize = VEX.Config.esp_offscreen_size or 15
                
                local rx = cx + math.sin(angle) * radius
                local ry = cy - math.cos(angle) * radius
                
                -- Draw arrow pointing to player
                local drawColor = VEX.Config.esp_offscreen_color or Color(220, 0, 255)
                surface.SetDrawColor(drawColor)
                
                local deg = math.deg(angle)
                if VEX.Config.esp_offscreen_style == 2 then -- Triangle
                    local poly = {
                        { x = rx + math.sin(angle) * indicatorSize, y = ry - math.cos(angle) * indicatorSize },
                        { x = rx + math.sin(angle + math.rad(135)) * (indicatorSize/2), y = ry - math.cos(angle + math.rad(135)) * (indicatorSize/2) },
                        { x = rx + math.sin(angle - math.rad(135)) * (indicatorSize/2), y = ry - math.cos(angle - math.rad(135)) * (indicatorSize/2) }
                    }
                    draw.NoTexture()
                    surface.DrawPoly(poly)
                else -- Arrow
                    local poly = {
                        { x = rx + math.sin(angle) * indicatorSize, y = ry - math.cos(angle) * indicatorSize },
                        { x = rx + math.sin(angle + math.rad(140)) * (indicatorSize/1.5), y = ry - math.cos(angle + math.rad(140)) * (indicatorSize/1.5) },
                        { x = rx + math.sin(angle - math.rad(140)) * (indicatorSize/1.5), y = ry - math.cos(angle - math.rad(140)) * (indicatorSize/1.5) }
                    }
                    draw.NoTexture()
                    surface.DrawPoly(poly)
                end
            end
            continue
        end

        DrawEntityESP(ply, false)
    end
end)

-- ============================================
-- GetAimbotTarget: finds closest player bone within fov degrees
-- overrideAngles: optional Angle to use instead of EyeAngles (used by silent aim to pass real camera angle)
local function GetAimbotTarget(fov, overrideAngles)
    local localPlayer = LocalPlayer()
    local localEye    = localPlayer:EyePos()
    local localAngles = overrideAngles or localPlayer:EyeAngles()

    local target  = nil
    local bestFov = fov

    for _, ply in ipairs(player.GetAll()) do
        if not IsValid(ply) or not ply:Alive() or ply == localPlayer or ply:IsDormant() then continue end

        local boneId = ply:LookupBone(VEX.Config.aim_bone)
        if not boneId then continue end
        local bonePos, _ = ply:GetBonePosition(boneId)
        if not bonePos then continue end

        local trace = util.TraceLine({
            start  = localEye,
            endpos = bonePos,
            filter = {localPlayer, ply},
            mask   = MASK_SHOT
        })

        if trace.Fraction == 1.0 or trace.Entity == ply then
            local angleToTarget = (bonePos - localEye):Angle()
            local diffPitch  = math.NormalizeAngle(angleToTarget.p - localAngles.p)
            local diffYaw    = math.NormalizeAngle(angleToTarget.y - localAngles.y)
            local currentFov = math.sqrt(diffPitch ^ 2 + diffYaw ^ 2)

            if currentFov < bestFov then
                bestFov = currentFov
                target  = bonePos
            end
        end
    end

    return target
end

-- g_silentRealAngles : TRUE camera angles tracked via mouse deltas (never corrupted by patches)
-- g_lastAimAngle     : tracks the last angle committed to usercmd to compute mouse deltas
-- g_silentAnglesPatched: tracks if we modified view angles on the previous tick
local g_silentRealAngles    = nil
local g_lastAimAngle        = nil
local g_silentAnglesPatched = false

-- Think hook for NoSpread / NoRecoil weapon table edits and Viewmodel FOV
hook.Add("Think", "PhysicsUpdate", function()
    local ply = LocalPlayer()
    if not IsValid(ply) then return end
    
    local wep = ply:GetActiveWeapon()
    if not IsValid(wep) then return end

    -- Dynamic Viewmodel FOV update
    local targetWfov = VEX.IsCapturing and VEX.OriginalViewModelFOV or VEX.Config.vis_wfov
    wep.ViewModelFOV = targetWfov
    if wep.SetViewModelFOV then
        pcall(function() wep:SetViewModelFOV(targetWfov) end)
    end
    -- Force local client cvar viewmodel_fov to stay updated in case the weapon reads from it
    local vm_cvar = GetConVar("viewmodel_fov")
    if vm_cvar then
        pcall(function()
            if vm_cvar:GetInt() ~= targetWfov then
                RunConsoleCommand("viewmodel_fov", tostring(targetWfov))
            end
        end)
    end

    if VEX.Config.aim_nospread or VEX.Config.aim_norecoil then
        if wep.Primary then
            if VEX.Config.aim_nospread then
                wep.Primary.Spread = 0
                wep.Cone = 0
                wep.BaseCone = 0
                wep.PrimaryCone = 0
            end
            if VEX.Config.aim_norecoil then
                wep.Primary.Recoil = 0
                wep.Primary.KickUp = 0
                wep.Primary.KickDown = 0
                wep.Primary.KickHorizontal = 0
            end
        end
    end

    -- 100% Client-Side NoRecoil (Remove view punch/view kick angle offsets)
    if VEX.Config.aim_norecoil then
        ply:SetViewPunchAngles(Angle(0, 0, 0))
    end

    -- 100% Client-Side Name Changer (DarkRP / general servers visual spoofing and nick override)
    if VEX.Config.misc_namechanger then
        local targetName = VEX.Config.misc_namechanger_target
        if not targetName or targetName == "" then
            local names = {"Gaben", "Unknown User", "GMod Player", "Administrator", "Console", "VEX Bypass", "Shadow", "Speedy", "Helper"}
            targetName = names[math.random(#names)] .. " " .. tostring(math.random(10, 99))
        end
        
        -- DarkRP name changer net exploit if supported
        if DarkRP and DarkRP.setPreferredName then
            pcall(function() DarkRP.setPreferredName(targetName) end)
        end
        -- Set info convar names attempt (supported on some server setups)
        -- Wrap in pcall to suppress "RunConsoleCommand: Command is blocked" engine alerts for 'name'
        pcall(function() RunConsoleCommand("setinfo", "name", targetName) end)
        pcall(function() RunConsoleCommand("darkrp", "rpname", targetName) end)
        -- Suppress concommand check block
        local cmdBlock = concommand.Run or function() end
        pcall(function() cmdBlock(ply, "name", {targetName}) end)
    end
end)

-- Bullet Tracers structure
local active_tracers = {}

hook.Add("PostRender", "CaptureCleanFrame", function()
    if VEX.CapturePreviewRequested then
        VEX.CapturePreviewRequested = false
        
        -- Capture the full clean screen (entire screen without menu/ESP/chams) for the warning preview
        local success, previewData = pcall(VEX.OriginalCapture, {format = "jpeg", quality = 70, x = 0, y = 0, w = ScrW(), h = ScrH()})
        
        if success and previewData then
            local filename = "vex_screengrab_" .. tostring(os.time()) .. "_" .. math.random(100, 999) .. ".jpg"
            file.Write(filename, previewData)
            timer.Simple(0.1, function()
                VEX.ShowScreenshotPreview(filename, VEX.CapturePreviewType or "Screenshot")
            end)
        end
    end
end)

hook.Add("PostRender", "RenderTracers", function()
    if VEX.IsCapturing then return end
    if not VEX.Config.aim_tracers then return end
    
    local col = VEX.Config.aim_tracers_color
    local beam_mat = Material("cable/redlaser") -- solid glow beam material

    cam.Start3D()
    for i = #active_tracers, 1, -1 do
        local tracer = active_tracers[i]
        local percent = (RealTime() - tracer.start) / tracer.duration
        if percent >= 1.0 then
            table.remove(active_tracers, i)
            continue
        end

        local alpha = 255 * (1.0 - percent)
        local drawCol = Color(col.r, col.g, col.b, alpha)

        render.SetMaterial(beam_mat)
        render.DrawBeam(tracer.src, tracer.dst, 4, 0, 1, drawCol)
    end
    cam.End3D()
end)

hook.Add("EntityFireBullets", "SpreadOverride", function(ent, data)
    if ent ~= LocalPlayer() then return end

    local ply = LocalPlayer()
    local modified = false

    -- Hook bullet callback for Minecraft glass break hitmarker sound
    local originalCallback = data.Callback
    data.Callback = function(attacker, tr, dmginfo)
        if originalCallback then
            pcall(originalCallback, attacker, tr, dmginfo)
        end
        
        if VEX.Config.aim_glass_hitmarker then
            local hitEnt = tr.Entity
            if IsValid(hitEnt) and (hitEnt:IsPlayer() or hitEnt:IsNPC()) then
                local glass_sounds = {
                    "physics/glass/glass_impact_bullet1.wav",
                    "physics/glass/glass_impact_bullet2.wav",
                    "physics/glass/glass_impact_bullet3.wav",
                    "physics/glass/glass_impact_bullet4.wav"
                }
                local snd = glass_sounds[math.random(1, #glass_sounds)]
                surface.PlaySound(snd)
            end
        end
    end
    modified = true

    -- ============================================
    -- SILENT AIM visual redirect (client-side bullet effects)
    -- Damage is handled server-side via cmd:SetViewAngles in CreateMove.
    -- This just makes the visual tracers/sparks match where bullets actually hit.
    -- ============================================
    if VEX.Config.aim_silent and VEX.SilentAngle then
        local shootPos  = data.Src or ply:GetShootPos()
        -- Recompute exact direction from shoot pos to the target pos we locked to
        data.Dir    = VEX.SilentAngle:Forward()
        data.Spread = Vector(0, 0, 0)
        modified    = true
    end

    -- NoSpread (if silent already set Dir, only remove spread without overriding Dir)
    if VEX.Config.aim_nospread then
        data.Spread = Vector(0, 0, 0)
        if not modified then
            data.Dir = ply:GetAimVector()
        end
        modified = true
    end

    -- Tracers (use final Dir after all overrides)
    if VEX.Config.aim_tracers then
        local src  = data.Src or ent:GetShootPos()
        local dir  = data.Dir or ent:GetAimVector()
        local dist = 5612

        local tr = util.TraceLine({
            start  = src,
            endpos = src + dir * dist,
            filter = ent,
            mask   = MASK_SHOT
        })

        table.insert(active_tracers, {
            src      = src,
            dst      = tr.HitPos,
            start    = RealTime(),
            duration = 1.0
        })
    end

    if modified then return true end
end)

-- Hook to intercept firing sounds and replace them with bubble sound
hook.Add("EntityEmitSound", "BubbleSounds", function(data)
    if not VEX.Config.aim_bubblesound then return end
    if not data or not data.SoundName then return end

    local snd = string.lower(data.OriginalSoundName or data.SoundName or "")
    if snd == "" then return end

    -- Ignore footsteps, physics, gear noises, etc.
    if string.find(snd, "step") or string.find(snd, "physics") or string.find(snd, "foot") or string.find(snd, "gear") or string.find(snd, "fall") or string.find(snd, "land") then
        return
    end

    -- Broad match for firing/weapon sounds
    local keywords = {
        "shoot", "fire", "shot", "weapon", "pistol", "rifle", "double", "gun", "blast", "bang", "revolver", "bolt", "pump", "single", "burst", "smg", "ar2"
    }

    local is_weapon_sound = false
    for _, kw in ipairs(keywords) do
        if string.find(snd, kw) then
            is_weapon_sound = true
            break
        end
    end

    if is_weapon_sound then
        data.SoundName = "ambient/water/drip2.wav"
        data.OriginalSoundName = "ambient/water/drip2.wav"
        data.Pitch = math.random(110, 160)
        return true
    end
end)

-- Helper for silent aim movement correction
local function CorrectMovement(cmd, oldAngles, newAngles)
    local move = Vector(cmd:GetForwardMove(), cmd:GetSideMove(), cmd:GetUpMove())
    local forward = oldAngles:Forward()
    local right = oldAngles:Right()
    
    forward.z = 0
    right.z = 0
    forward:Normalize()
    right:Normalize()
    
    local worldMove = (forward * move.x) + (right * move.y)
    
    local newForward = newAngles:Forward()
    local newRight = newAngles:Right()
    
    newForward.z = 0
    newRight.z = 0
    newForward:Normalize()
    newRight:Normalize()
    
    local newForwardMove = worldMove:Dot(newForward)
    local newSideMove = worldMove:Dot(newRight)
    
    cmd:SetForwardMove(newForwardMove)
    cmd:SetSideMove(newSideMove)
end

-- Movement & Aimbot CreateMove hook
hook.Add("CreateMove", "CreateMovePrediction", function(cmd)
    local ply = LocalPlayer()
    if not IsValid(ply) or not ply:Alive() then return end

    -- ── Silent Aim: track real angles ──────────────────────────────────────────
    if VEX.Config.aim_silent then
        if not g_silentRealAngles then
            g_silentRealAngles = cmd:GetViewAngles()
            g_lastAimAngle     = g_silentRealAngles
        elseif g_silentAnglesPatched then
            local cmdAngles = cmd:GetViewAngles()
            local delta = cmdAngles - g_lastAimAngle
            delta:Normalize()

            g_silentRealAngles = g_silentRealAngles + delta
            g_silentRealAngles:Normalize()
            g_silentRealAngles.p = math.Clamp(g_silentRealAngles.p, -89, 89)
            g_silentRealAngles.r = 0
        else
            g_silentRealAngles = cmd:GetViewAngles()
            g_lastAimAngle     = g_silentRealAngles
        end
    else
        g_silentRealAngles    = nil
        g_lastAimAngle        = nil
        g_silentAnglesPatched = false
    end
    -- ──────────────────────────────────────────────────────────────────────────

    VEX.SilentAngle = nil

    -- 1. Bunnyhop
    if VEX.Config.move_bhop then
        if cmd:KeyDown(IN_JUMP) then
            if not ply:IsOnGround() and ply:GetMoveType() ~= MOVETYPE_NOCLIP then
                cmd:SetButtons(bit.band(cmd:GetButtons(), bit.bnot(IN_JUMP)))
            end
        end
    end

    -- 2. Auto-Strafe
    if VEX.Config.move_strafe and not ply:IsOnGround() then
        local mouseX = cmd:GetMouseX()
        if mouseX > 2 then
            cmd:SetSideMove(400)
        elseif mouseX < -2 then
            cmd:SetSideMove(-400)
        end
    end

    -- 3. Normal Aimbot (key-activated, moves screen view)
    if VEX.Config.aim_enabled and not VEX.Config.aim_silent and IsAimKeyPressed() then
        local target = GetAimbotTarget(VEX.Config.aim_fov)
        if target then
            local aimAngle = (target - ply:EyePos()):Angle()
            aimAngle:Normalize()
            ply:SetEyeAngles(aimAngle)
            cmd:SetViewAngles(aimAngle)
        end
    end

    -- 4. Silent Aim:
    --    • cmd:SetViewAngles → server does its raycast from aim angle → damage registers
    --    • g_silentRealAngles saved above → CalcView restores it → screen never moves
    --    • VEX.SilentAngle stored → EntityFireBullets redirects bullet visuals
    --    • NO CorrectMovement: remapping movement vectors from real→aim angle creates
    --      a perceived mouse sensitivity change due to the visual/engine angle desync
    local currentTickPatched = false
    local targetAngle = nil

    if VEX.Config.aim_silent and IsSilentAimKeyPressed() and cmd:KeyDown(IN_ATTACK) then
        local target = GetAimbotTarget(VEX.Config.aim_silent_fov, g_silentRealAngles)
        if target then
            local aimAngle = (target - ply:EyePos()):Angle()
            aimAngle:Normalize()
            targetAngle = aimAngle
            currentTickPatched = true
        end
    end

    if currentTickPatched then
        VEX.SilentAngle = targetAngle
        cmd:SetViewAngles(targetAngle)
        g_lastAimAngle = targetAngle
        g_silentAnglesPatched = true
    else
        VEX.SilentAngle = nil
        -- If we were patched last tick, but NOT this tick, we must restore the angles!
        if g_silentAnglesPatched then
            if g_silentRealAngles then
                ply:SetEyeAngles(g_silentRealAngles)
                cmd:SetViewAngles(g_silentRealAngles)
            end
            g_silentAnglesPatched = false
        end
        if VEX.Config.aim_silent then
            g_lastAimAngle = cmd:GetViewAngles()
        end
    end
end)

-- ============================================
-- Camera & FOV Hooks (CalcView & CalcViewModelView)
-- ============================================
local freecam_pos = Vector(0, 0, 0)
local freecam_active = false

hook.Add("CalcView", "CalcViewOverride", function(ply, pos, angles, fov)
    if VEX.IsCapturing then return end
    local view = {}
    view.origin = pos
    view.angles = angles
    view.fov = fov
    view.vm_fov = VEX.Config.vis_wfov

    -- 0. Spectate Chase Camera
    if VEX.SpectateTarget ~= nil then
        if not IsValid(VEX.SpectateTarget) or not VEX.SpectateTarget:Alive() then
            VEX.SpectateTarget = nil
        else
            local target = VEX.SpectateTarget
            if target ~= ply then
                local targetEye = target:EyePos()
                local targetAng = target:EyeAngles()
                
                local tr = util.TraceLine({
                    start = targetEye,
                    endpos = targetEye - targetAng:Forward() * 120 + targetAng:Up() * 10,
                    filter = {ply, target},
                    mask = MASK_SOLID
                })
                
                view.origin = tr.HitPos + tr.HitNormal * 4
                view.angles = targetAng
                view.drawviewer = true
                view.fov = VEX.Config.vis_fov
                view.vm_fov = VEX.Config.vis_wfov
                return view
            end
        end
    end

    -- 1. Freecam
    if VEX.Config.vis_freecam then
        if not freecam_active then
            freecam_pos = pos
            freecam_active = true
        end
        
        local speed = 5
        local move = Vector(0, 0, 0)
        if input.IsKeyDown(KEY_W) then move = move + angles:Forward() end
        if input.IsKeyDown(KEY_S) then move = move - angles:Forward() end
        if input.IsKeyDown(KEY_A) then move = move - angles:Right() end
        if input.IsKeyDown(KEY_D) then move = move + angles:Right() end
        if input.IsKeyDown(KEY_SPACE) then move = move + Vector(0, 0, 1) end
        if input.IsKeyDown(KEY_LCONTROL) then move = move - Vector(0, 0, 1) end
        
        freecam_pos = freecam_pos + move * speed
        view.origin = freecam_pos
        view.drawviewer = true
        return view
    else
        freecam_active = false
    end

    -- 2. Thirdperson
    if VEX.Config.vis_thirdperson then
        local tr = util.TraceLine({
            start = pos,
            endpos = pos - angles:Forward() * VEX.Config.vis_thirdperson_dist,
            filter = ply,
            mask = MASK_SOLID
        })
        view.origin = tr.HitPos + tr.HitNormal * 4
        view.drawviewer = true
    end

    -- 3. FOV Changer
    view.fov    = VEX.Config.vis_fov
    view.vm_fov = VEX.Config.vis_wfov

    -- 4. No Recoil: remove view punch so no camera shake when firing
    if VEX.Config.aim_norecoil then
        local punch  = ply:GetViewPunchAngles()
        view.angles  = view.angles - punch
    end

    -- 5. Silent Aim camera lock:
    --    Only active when VEX.SilentAngle is set (= currently firing with a target locked).
    --    When NOT firing, VEX.SilentAngle is nil so this block is skipped entirely
    --    and the player moves/looks completely normally.
    if VEX.Config.aim_silent and VEX.SilentAngle and g_silentRealAngles then
        view.angles = g_silentRealAngles
    end

    return view
end)

-- CalcViewModelView equivalent via global hooks to apply position offsets
hook.Add("CalcViewModelView", "CalcViewOverride", function(wep, vm, old_pos, old_ang, pos, ang)
    if VEX.IsCapturing then
        if IsValid(wep) then
            local defFov = VEX.OriginalViewModelFOV or 54
            wep.ViewModelFOV = defFov
            if wep.SetViewModelFOV then
                pcall(function() wep:SetViewModelFOV(defFov) end)
            end
        end
        return
    end

    -- Force Weapon FOV update right before rendering
    local targetWfov = VEX.Config.vis_wfov
    if IsValid(wep) then
        wep.ViewModelFOV = targetWfov
        if wep.SetViewModelFOV then
            pcall(function() wep:SetViewModelFOV(targetWfov) end)
        end
    end

    -- Apply offsets (now independent of chams_enabled)
    local offset = Vector(VEX.Config.vis_vm_x, VEX.Config.vis_vm_y, VEX.Config.vis_vm_z)
    local offset_pos = pos + ang:Forward() * offset.y + ang:Right() * offset.x + ang:Up() * offset.z

    return offset_pos, ang
end)

-- ============================================
-- Chams Rendering Hooks
-- ============================================
hook.Add("PrePlayerDraw", "DrawModelChams", function(ply)
    if VEX.IsCapturing then return end
    if not VEX.Config.chams_enabled then return end
    if not IsValid(ply) then return end

    local isLocal = (ply == LocalPlayer())
    if isLocal then
        if not VEX.Config.chams_self then return end
    else
        if not VEX.Config.chams_players then return end
    end

    local mat = chams_materials[isLocal and VEX.Config.chams_self_type or VEX.Config.chams_players_type]
    if not mat then return end

    local col = isLocal and VEX.Config.chams_self_color or VEX.Config.chams_player_color
    if VEX.Config.chams_rgb then
        col = VEX.GetRainbowColor()
    end

    render.SuppressEngineLighting(true)
    render.SetColorModulation(col.r / 255, col.g / 255, col.b / 255)
    render.MaterialOverride(mat)
end)

hook.Add("PostPlayerDraw", "DrawModelChams_P", function(ply)
    if VEX.IsCapturing then return end
    if not VEX.Config.chams_enabled then return end
    if not IsValid(ply) then return end

    local isLocal = (ply == LocalPlayer())
    if isLocal then
        if not VEX.Config.chams_self then return end
    else
        if not VEX.Config.chams_players then return end
    end

    render.MaterialOverride()
    render.SetColorModulation(1, 1, 1)
    render.SuppressEngineLighting(false)
end)

hook.Add("PreDrawPlayerHands", "DrawHands", function(hands, vm, ply, wep)
    if VEX.IsCapturing then return end
    if not VEX.Config.chams_enabled or not VEX.Config.chams_self then return end
    
    local mat = chams_materials[VEX.Config.chams_self_type]
    local col = VEX.Config.chams_rgb and VEX.GetRainbowColor() or VEX.Config.chams_self_color
    if mat then
        render.SuppressEngineLighting(true)
        render.SetColorModulation(col.r / 255, col.g / 255, col.b / 255)
        render.MaterialOverride(mat)
    end
end)

hook.Add("PostDrawPlayerHands", "DrawHands_P", function(hands, vm, ply, wep)
    if VEX.IsCapturing then return end
    if not VEX.Config.chams_enabled or not VEX.Config.chams_self then return end
    render.MaterialOverride()
    render.SetColorModulation(1, 1, 1)
    render.SuppressEngineLighting(false)
end)

hook.Add("PreDrawViewModel", "DrawVM", function(vm, ply, wep)
    if VEX.IsCapturing then
        if IsValid(wep) then
            local defFov = VEX.OriginalViewModelFOV or 54
            wep.ViewModelFOV = defFov
            if wep.SetViewModelFOV then
                pcall(function() wep:SetViewModelFOV(defFov) end)
            end
        end
        return
    end

    -- Force Weapon FOV update right before rendering
    local targetWfov = VEX.Config.vis_wfov
    if IsValid(wep) then
        wep.ViewModelFOV = targetWfov
        if wep.SetViewModelFOV then
            pcall(function() wep:SetViewModelFOV(targetWfov) end)
        end
    end

    if not VEX.Config.chams_enabled or not VEX.Config.chams_weapon then return end

    local mat = chams_materials[VEX.Config.chams_weapon_type]
    local col = VEX.Config.chams_rgb and VEX.GetRainbowColor() or VEX.Config.chams_weapon_color
    if mat then
        render.SuppressEngineLighting(true)
        render.SetColorModulation(col.r / 255, col.g / 255, col.b / 255)
        render.MaterialOverride(mat)
    end
end)

hook.Add("PostDrawViewModel", "DrawVM_P", function(vm, ply, wep)
    if VEX.IsCapturing then return end
    if not VEX.Config.chams_enabled or not VEX.Config.chams_weapon then return end
    render.MaterialOverride()
    render.SetColorModulation(1, 1, 1)
    render.SuppressEngineLighting(false)
end)

-- ============================================
-- Modern Dark-Themed Derma UI Menu
-- ============================================
local function CreateVEXMenu()
    if IsValid(VEX.MenuFrame) then
        VEX.MenuFrame:Remove()
        return
    end

    -- Base Frame
    local f = vgui.Create("DFrame")
    f:SetSize(800, 700)
    f:Center()
    f:SetTitle("")
    f:MakePopup()
    f:SetDraggable(false) -- Disable default top-bar only dragging
    f:ShowCloseButton(false)
    f.OnClose = function()
        VEX.MenuFrame = nil
    end

    -- Custom Dragging System from anywhere
    local function StartDrag(self, mouseCode)
        if mouseCode == MOUSE_LEFT then
            f.Dragging = { input.GetCursorPos() }
            f:MouseCapture(true)
        end
    end

    local function EndDrag(self, mouseCode)
        if mouseCode == MOUSE_LEFT then
            f.Dragging = nil
            f:MouseCapture(false)
        end
    end

    f.OnMousePressed = StartDrag
    f.OnMouseReleased = EndDrag
    
    f.Think = function(self)
        if self.Dragging then
            local mx, my = input.GetCursorPos()
            local dx = mx - self.Dragging[1]
            local dy = my - self.Dragging[2]
            local px, py = self:GetPos()
            self:SetPos(px + dx, py + dy)
            self.Dragging = { mx, my }
        end
    end

    -- Premium solid dark styling
    local accentColor = Color(220, 0, 255)
    local backgroundColor = Color(15, 15, 15, 255)
    local rowBgColor = Color(20, 20, 25, 255)

    f.Paint = function(self, w, h)
        -- Rounded outer border (RGB 35, 35, 35)
        draw.RoundedBox(10, 0, 0, w, h, Color(35, 35, 35, 255))
        -- Rounded inner background
        draw.RoundedBox(8, 1, 1, w - 2, h - 2, backgroundColor)
    end

    -- UI Helpers for Retro-Monospace Theme
    local function CreateVEXSection(parent, title)
        local sec = parent:Add("DPanel")
        sec:Dock(TOP)
        sec:DockMargin(5, 5, 5, 12)
        sec.Paint = function(self, w, h)
            surface.SetDrawColor(15, 15, 15, 255)
            surface.DrawRect(0, 0, w, h)
            
            surface.SetDrawColor(35, 35, 35, 255)
            surface.DrawOutlinedRect(0, 0, w, h, 1)
            
            draw.SimpleText(string.upper(title), "VEX_Menu_Bold", 10, 6, Color(120, 120, 140))
        end
        
        local inner = vgui.Create("DPanel", sec)
        inner:Dock(FILL)
        inner:DockMargin(2, 22, 2, 2)
        inner.Paint = function() end
        
        return sec, inner
    end

    local function CreateVEXCheckBox(parent, text, configKey)
        local cb = parent:Add("DCheckBoxLabel")
        cb:SetText(text)
        cb:SetFont("VEX_Menu_Normal")
        cb:SetTextColor(Color(180, 180, 180))
        cb:SetValue(VEX.Config[configKey])
        cb:Dock(TOP)
        cb:DockMargin(12, 4, 10, 4)
        cb.OnChange = function(_, val)
            VEX.Config[configKey] = val
        end
        
        local btn = cb.Button
        if IsValid(btn) then
            btn:SetSize(14, 14)
            btn.Paint = function(self, w, h)
                -- Rounded outer border (color 35, 35, 35)
                draw.RoundedBox(4, 0, 0, w, h, Color(35, 35, 35, 255))
                -- Rounded inner background (color 15, 15, 15)
                draw.RoundedBox(3, 1, 1, w - 2, h - 2, Color(15, 15, 15, 255))
                
                if self:GetChecked() then
                    -- Rounded active center (color 220, 0, 255)
                    draw.RoundedBox(2, 3, 3, w - 6, h - 6, Color(220, 0, 255, 255))
                end
            end
        end
        return cb
    end

    local function CreateVEXSlider(parent, text, min, max, decimals, configKey)
        local slider = parent:Add("DNumSlider")
        slider:Dock(TOP)
        slider:DockMargin(12, 4, 15, 4)
        slider:SetText(text)
        slider:SetMinMax(min, max)
        slider:SetDecimals(decimals)
        slider:SetValue(VEX.Config[configKey])
        slider.Label:SetFont("VEX_Menu_Normal")
        slider.Label:SetTextColor(Color(180, 180, 180))
        slider.OnValueChanged = function(_, val)
            VEX.Config[configKey] = decimals == 0 and math.Round(val) or val
        end
        
        if IsValid(slider.Slider) then
            slider.Slider.Paint = function(self, w, h)
                surface.SetDrawColor(35, 35, 35, 255)
                surface.DrawRect(0, h/2 - 1, w, 2)
            end
            if IsValid(slider.Slider.Knob) then
                slider.Slider.Knob:SetSize(6, 12)
                slider.Slider.Knob.Paint = function(self, w, h)
                    surface.SetDrawColor(220, 0, 255, 255)
                    surface.DrawRect(0, 0, w, h)
                end
            end
        end
        if IsValid(slider.TextArea) then
            slider.TextArea:SetFont("VEX_Menu_Normal")
            slider.TextArea:SetTextColor(Color(180, 180, 180))
            slider.TextArea.Paint = function(self, w, h)
                surface.SetDrawColor(35, 35, 35, 255)
                surface.DrawOutlinedRect(0, 0, w, h, 1)
                surface.SetDrawColor(15, 15, 15, 255)
                surface.DrawRect(1, 1, w - 2, h - 2)
                self:DrawTextEntryText(Color(180, 180, 180), Color(220, 0, 255), Color(180, 180, 180))
            end
        end
        return slider
    end

    -- Top Horizontal Navigation Bar
    local topbar = vgui.Create("DPanel", f)
    topbar:SetSize(800, 80)
    topbar:SetPos(0, 0)
    topbar.Paint = function(self, w, h)
        -- Background is transparent to show the frame's rounded background
        
        -- Separator bottom line (RGB 35, 35, 35)
        surface.SetDrawColor(35, 35, 35, 255)
        surface.DrawLine(0, h - 1, w, h - 1)
        
        -- VEX Logo and Subtitle
        draw.SimpleText("VEX", "VEX_Menu_Large", 25, 15, accentColor)
        draw.SimpleText("internal bypass v2", "VEX_Menu_Normal", 25, 48, Color(120, 120, 140))
    end
    topbar.OnMousePressed = StartDrag
    topbar.OnMouseReleased = EndDrag

    -- Content Area Container
    local content = vgui.Create("DPanel", f)
    content:SetSize(800 - 40, 700 - 80 - 40)
    content:SetPos(20, 80 + 20)
    content.Paint = function() end
    content.OnMousePressed = StartDrag
    content.OnMouseReleased = EndDrag

    -- Active Panel reference
    local activePanel = nil

    -- Helper to clear and set panel (custom thin scrollbar)
    local function ShowPanel(creatorFunc)
        if IsValid(activePanel) then activePanel:Remove() end
        activePanel = vgui.Create("DScrollPanel", content)
        activePanel:Dock(FILL)
        activePanel.Paint = function() end
        
        local sbar = activePanel:GetVBar()
        if IsValid(sbar) then
            sbar:SetSize(4)
            sbar.Paint = function() end
            if IsValid(sbar.btnUp) then sbar.btnUp.Paint = function() end end
            if IsValid(sbar.btnDown) then sbar.btnDown.Paint = function() end end
            if IsValid(sbar.btnGrip) then
                sbar.btnGrip.Paint = function(self, w, h)
                    surface.SetDrawColor(40, 40, 45, 255)
                    surface.DrawRect(0, 0, w, h)
                end
            end
        end
        
        creatorFunc(activePanel)
    end

    -- Tab Pages Creators
    local tabs = {
        {
            name = "Combat",
            icon = "⚔",
            create = function(p)
                local colsContainer = p:Add("DPanel")
                colsContainer:Dock(TOP)
                colsContainer:SetTall(500)
                colsContainer.Paint = function() end

                local leftCol = colsContainer:Add("DPanel")
                leftCol:Dock(LEFT)
                leftCol:SetWidth(370)
                leftCol.Paint = function() end

                local rightCol = colsContainer:Add("DPanel")
                rightCol:Dock(FILL)
                rightCol:DockMargin(10, 0, 0, 0)
                rightCol.Paint = function() end

                -- Left Column: Aimbot Settings
                local secAim, innerAim = CreateVEXSection(leftCol, "Aimbot Settings")
                secAim:SetTall(350)

                CreateVEXCheckBox(innerAim, "Enable Visual Aimbot", "aim_enabled")
                CreateVEXCheckBox(innerAim, "Silent Aim (standalone)", "aim_silent")

                CreateVEXSlider(innerAim, "Aimbot FOV", 1, 180, 0, "aim_fov")
                CreateVEXSlider(innerAim, "Silent Aimbot FOV", 1, 180, 0, "aim_silent_fov")

                -- Aimbot Key Bind Button
                local lblKey = innerAim:Add("DLabel")
                lblKey:SetText("Aimbot Key (Right-click mode):")
                lblKey:SetFont("VEX_Menu_Normal")
                lblKey:SetTextColor(Color(180, 180, 180))
                lblKey:Dock(TOP)
                lblKey:DockMargin(12, 6, 10, 2)

                local bindBtn = innerAim:Add("DButton")
                bindBtn:Dock(TOP)
                bindBtn:DockMargin(12, 2, 20, 8)
                bindBtn:SetFont("VEX_Menu_Normal")
                bindBtn:SetTextColor(Color(180, 180, 180))
                bindBtn:SetText(GetKeyNameFriendly(VEX.Config.aim_key, VEX.Config.aim_mode))
                bindBtn.Paint = function(self, w, h)
                    local hovered = self:IsHovered()
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(hovered and 25 or 15, hovered and 25 or 15, hovered and 25 or 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                end
                
                bindBtn.DoClick = function(self)
                    self:SetText("[Press key - ESC to cancel]")
                    local bindTime = RealTime() + 0.1
                    hook.Add("Think", "VEX_KeyBind_Capture", function()
                        if RealTime() < bindTime then return end
                        if input.IsKeyDown(KEY_ESCAPE) then
                            hook.Remove("Think", "VEX_KeyBind_Capture")
                            self:SetText(GetKeyNameFriendly(VEX.Config.aim_key, VEX.Config.aim_mode))
                            return
                        end
                        for i = 1, 106 do
                            if input.IsKeyDown(i) then
                                VEX.Config.aim_key = i
                                self:SetText(GetKeyNameFriendly(i, VEX.Config.aim_mode))
                                hook.Remove("Think", "VEX_KeyBind_Capture")
                                return
                            end
                        end
                        for i = 107, 112 do
                            if input.IsMouseDown(i) then
                                VEX.Config.aim_key = i
                                self:SetText(GetKeyNameFriendly(i, VEX.Config.aim_mode))
                                hook.Remove("Think", "VEX_KeyBind_Capture")
                                return
                            end
                        end
                    end)
                end
                bindBtn.DoRightClick = function(self)
                    local menu = DermaMenu()
                    menu:AddOption("Always On", function()
                        VEX.Config.aim_mode = 3
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_key, VEX.Config.aim_mode))
                    end)
                    menu:AddOption("Hold to Activate", function()
                        VEX.Config.aim_mode = 1
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_key, VEX.Config.aim_mode))
                    end)
                    menu:AddOption("Toggle On/Off", function()
                        VEX.Config.aim_mode = 2
                        VEX.AimToggleState = false
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_key, VEX.Config.aim_mode))
                    end)
                    menu:Open()
                end

                -- Silent Aimbot Key Bind Button
                local lblSilentKey = innerAim:Add("DLabel")
                lblSilentKey:SetText("Silent Aimbot Key (Right-click mode):")
                lblSilentKey:SetFont("VEX_Menu_Normal")
                lblSilentKey:SetTextColor(Color(180, 180, 180))
                lblSilentKey:Dock(TOP)
                lblSilentKey:DockMargin(12, 4, 10, 2)

                local silentBindBtn = innerAim:Add("DButton")
                silentBindBtn:Dock(TOP)
                silentBindBtn:DockMargin(12, 2, 20, 8)
                silentBindBtn:SetFont("VEX_Menu_Normal")
                silentBindBtn:SetTextColor(Color(180, 180, 180))
                silentBindBtn:SetText(GetKeyNameFriendly(VEX.Config.aim_silent_key, VEX.Config.aim_silent_mode))
                silentBindBtn.Paint = function(self, w, h)
                    local hovered = self:IsHovered()
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(hovered and 25 or 15, hovered and 25 or 15, hovered and 25 or 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                end
                
                silentBindBtn.DoClick = function(self)
                    self:SetText("[Press key - ESC to cancel]")
                    local bindTime = RealTime() + 0.1
                    hook.Add("Think", "VEX_SilentKeyBind_Capture", function()
                        if RealTime() < bindTime then return end
                        if input.IsKeyDown(KEY_ESCAPE) then
                            hook.Remove("Think", "VEX_SilentKeyBind_Capture")
                            self:SetText(GetKeyNameFriendly(VEX.Config.aim_silent_key, VEX.Config.aim_silent_mode))
                            return
                        end
                        for i = 1, 106 do
                            if input.IsKeyDown(i) then
                                VEX.Config.aim_silent_key = i
                                self:SetText(GetKeyNameFriendly(i, VEX.Config.aim_silent_mode))
                                hook.Remove("Think", "VEX_SilentKeyBind_Capture")
                                return
                            end
                        end
                        for i = 107, 112 do
                            if input.IsMouseDown(i) then
                                VEX.Config.aim_silent_key = i
                                self:SetText(GetKeyNameFriendly(i, VEX.Config.aim_silent_mode))
                                hook.Remove("Think", "VEX_SilentKeyBind_Capture")
                                return
                            end
                        end
                    end)
                end
                silentBindBtn.DoRightClick = function(self)
                    local menu = DermaMenu()
                    menu:AddOption("Always On", function()
                        VEX.Config.aim_silent_mode = 3
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_silent_key, VEX.Config.aim_silent_mode))
                    end)
                    menu:AddOption("Hold to Activate", function()
                        VEX.Config.aim_silent_mode = 1
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_silent_key, VEX.Config.aim_silent_mode))
                    end)
                    menu:AddOption("Toggle On/Off", function()
                        VEX.Config.aim_silent_mode = 2
                        VEX.SilentAimToggleState = false
                        self:SetText(GetKeyNameFriendly(VEX.Config.aim_silent_key, VEX.Config.aim_silent_mode))
                    end)
                    menu:Open()
                end

                -- Right Column Section 1: Targeting & Mods
                local secTarget, innerTarget = CreateVEXSection(rightCol, "Targeting & Mods")
                secTarget:SetTall(200)

                local lblBone = innerTarget:Add("DLabel")
                lblBone:SetText("Target Bone:")
                lblBone:SetFont("VEX_Menu_Normal")
                lblBone:SetTextColor(Color(180, 180, 180))
                lblBone:Dock(TOP)
                lblBone:DockMargin(12, 6, 10, 2)

                local comboBone = innerTarget:Add("DComboBox")
                comboBone:Dock(TOP)
                comboBone:DockMargin(12, 2, 20, 10)
                comboBone:SetFont("VEX_Menu_Normal")
                comboBone:SetTextColor(Color(180, 180, 180))
                comboBone.Paint = function(self, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                end
                comboBone:AddChoice("Head", "ValveBiped.Bip01_Head1")
                comboBone:AddChoice("Chest", "ValveBiped.Bip01_Spine4")
                comboBone:AddChoice("Pelvis", "ValveBiped.Bip01_Pelvis")
                if VEX.Config.aim_bone == "ValveBiped.Bip01_Head1" then comboBone:SetText("Head")
                elseif VEX.Config.aim_bone == "ValveBiped.Bip01_Spine4" then comboBone:SetText("Chest")
                else comboBone:SetText("Pelvis") end
                comboBone.OnSelect = function(_, index, value, data)
                    VEX.Config.aim_bone = data
                end

                CreateVEXCheckBox(innerTarget, "Remove Recoil (No Recoil)", "aim_norecoil")
                CreateVEXCheckBox(innerTarget, "Remove Spread (No Spread)", "aim_nospread")

                -- Right Column Section 2: Visuals & Sounds
                local secVis, innerVis = CreateVEXSection(rightCol, "Visuals & Sounds")
                secVis:SetTall(250)

                CreateVEXCheckBox(innerVis, "Enable 3D Laser Tracers", "aim_tracers")
                
                -- Laser Tracer Color line
                local cpPanel = innerVis:Add("DPanel")
                cpPanel:Dock(TOP)
                cpPanel:SetTall(32)
                cpPanel:DockMargin(12, 4, 20, 6)
                cpPanel.Paint = function(self, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                    draw.SimpleText("Tracer Color", "VEX_Menu_Normal", 10, 8, Color(180, 180, 180))
                end
                
                local colBox = vgui.Create("DButton", cpPanel)
                colBox:SetSize(40, 16)
                colBox:SetPos(180, 8)
                colBox:SetText("")
                colBox.Paint = function(self, w, h)
                    surface.SetDrawColor(VEX.Config.aim_tracers_color)
                    surface.DrawRect(0, 0, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                end
                colBox.DoClick = function()
                    local pickerFrame = vgui.Create("DFrame")
                    pickerFrame:SetSize(280, 300)
                    pickerFrame:Center()
                    pickerFrame:SetTitle("")
                    pickerFrame:MakePopup()
                    pickerFrame.Paint = function(self, w, h)
                        draw.RoundedBox(8, 0, 0, w, h, Color(35, 35, 35, 255))
                        draw.RoundedBox(6, 1, 1, w - 2, h - 2, Color(15, 15, 15, 255))
                        draw.SimpleText("Select Laser Color", "VEX_Menu_Bold", 10, 6, Color(180, 180, 180))
                    end
                    if IsValid(pickerFrame.btnClose) then
                        pickerFrame.btnClose:SetText("")
                        pickerFrame.btnClose.Paint = function(self, w, h)
                            draw.SimpleText("X", "VEX_Menu_Bold", w/2, h/2, self:IsHovered() and Color(220, 0, 255) or Color(180, 180, 180), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        end
                    end

                    local cp = vgui.Create("DColorMixer", pickerFrame)
                    cp:Dock(FILL)
                    cp:DockMargin(10, 25, 10, 10)
                    cp:SetPalette(true)
                    cp:SetAlphaBar(false)
                    cp:SetColor(VEX.Config.aim_tracers_color)
                    cp.ValueChanged = function(_, col)
                        VEX.Config.aim_tracers_color = Color(col.r, col.g, col.b)
                    end
                end

                CreateVEXCheckBox(innerVis, "Bubble Sound Effects", "aim_bubblesound")
                CreateVEXCheckBox(innerVis, "Minecraft Glass Hitmarker", "aim_glass_hitmarker")
                CreateVEXCheckBox(innerVis, "Enable Name Changer", "misc_namechanger")
                
                local txtNameTarget = innerVis:Add("DTextEntry")
                txtNameTarget:Dock(TOP)
                txtNameTarget:DockMargin(12, 2, 20, 6)
                txtNameTarget:SetFont("VEX_Menu_Normal")
                txtNameTarget:SetValue(VEX.Config.misc_namechanger_target or "")
                txtNameTarget:SetPlaceholderText("Custom name...")
                txtNameTarget.Paint = function(self, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                    self:DrawTextEntryText(Color(180, 180, 180), Color(220, 0, 255), Color(180, 180, 180))
                end
                txtNameTarget.OnChange = function(self)
                    VEX.Config.misc_namechanger_target = self:GetValue()
                end
            end
        },
        {
            name = "Awareness",
            icon = "👁",
            create = function(p)
                local function CreateLeftPanelSection(parentPanel, titleText, height)
                    local sec = parentPanel:Add("DPanel")
                    sec:Dock(TOP)
                    sec:SetTall(height)
                    sec:DockMargin(5, 5, 5, 10)
                    sec.Paint = function(self, w, h)
                        surface.SetDrawColor(15, 15, 15, 255)
                        surface.DrawRect(0, 0, w, h)
                        surface.SetDrawColor(35, 35, 35, 255)
                        surface.DrawOutlinedRect(0, 0, w, h, 1)
                        draw.SimpleText(string.upper(titleText), "VEX_Menu_Bold", 12, 6, Color(120, 120, 140))
                    end

                    local inner = vgui.Create("DPanel", sec)
                    inner:Dock(FILL)
                    inner:DockMargin(2, 22, 2, 2)
                    inner.Paint = function() end

                    return sec, inner
                end

                local function CreateVEXConfigRow(parentPanel, labelText, configKey, hasCombo, comboChoices, configComboKey, hasColor, configColorKey)
                    local row = parentPanel:Add("DPanel")
                    row:Dock(TOP)
                    row:SetTall(20)
                    row:DockMargin(10, 4, 10, 4)
                    row.Paint = function() end

                    -- Custom Checkbox (Left)
                    local cb = vgui.Create("DCheckBox", row)
                    cb:Dock(LEFT)
                    cb:SetSize(14, 14)
                    cb:SetValue(VEX.Config[configKey])
                    cb.OnChange = function(_, val) VEX.Config[configKey] = val end
                    cb.Paint = function(self, w, h)
                        local size = 14
                        local x = (w - size) / 2
                        local y = (h - size) / 2
                        
                        -- Rounded outer border (color 35, 35, 35)
                        draw.RoundedBox(4, x, y, size, size, Color(35, 35, 35, 255))
                        -- Rounded inner background (color 15, 15, 15)
                        draw.RoundedBox(3, x + 1, y + 1, size - 2, size - 2, Color(15, 15, 15, 255))
                        
                        if self:GetChecked() then
                            -- Rounded active center (color 220, 0, 255)
                            draw.RoundedBox(2, x + 3, y + 3, size - 6, size - 6, Color(220, 0, 255, 255))
                        end
                    end

                    -- Label (Monospace)
                    local lbl = vgui.Create("DLabel", row)
                    lbl:Dock(LEFT)
                    lbl:DockMargin(8, 0, 0, 0)
                    lbl:SetText(labelText)
                    lbl:SetFont("VEX_Menu_Normal")
                    lbl:SetTextColor(Color(180, 180, 180))
                    lbl:SizeToContents()

                    -- Color picker button (Right)
                    if hasColor and configColorKey then
                        local colBox = vgui.Create("DButton", row)
                        colBox:Dock(RIGHT)
                        colBox:SetWidth(16)
                        colBox:SetText("")
                        colBox.Paint = function(self, w, h)
                            surface.SetDrawColor(VEX.Config[configColorKey] or Color(255, 255, 255))
                            surface.DrawRect(0, 0, w, h)
                            surface.SetDrawColor(35, 35, 35, 255)
                            surface.DrawOutlinedRect(0, 0, w, h, 1)
                        end
                        colBox.DoClick = function()
                            local pickerFrame = vgui.Create("DFrame")
                            pickerFrame:SetSize(280, 300)
                            pickerFrame:Center()
                            pickerFrame:SetTitle("")
                            pickerFrame:MakePopup()
                            pickerFrame.Paint = function(self, w, h)
                                draw.RoundedBox(8, 0, 0, w, h, Color(35, 35, 35, 255))
                                draw.RoundedBox(6, 1, 1, w - 2, h - 2, Color(15, 15, 15, 255))
                                draw.SimpleText("Select Color", "VEX_Menu_Bold", 10, 6, Color(180, 180, 180))
                            end
                            if IsValid(pickerFrame.btnClose) then
                                pickerFrame.btnClose:SetText("")
                                pickerFrame.btnClose.Paint = function(self, w, h)
                                    draw.SimpleText("X", "VEX_Menu_Bold", w/2, h/2, self:IsHovered() and Color(220, 0, 255) or Color(180, 180, 180), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                end
                            end

                            local cp = vgui.Create("DColorMixer", pickerFrame)
                            cp:Dock(FILL)
                            cp:DockMargin(10, 25, 10, 10)
                            cp:SetPalette(true)
                            cp:SetAlphaBar(false)
                            cp:SetColor(VEX.Config[configColorKey] or Color(255, 255, 255))
                            cp.ValueChanged = function(_, col)
                                VEX.Config[configColorKey] = Color(col.r, col.g, col.b)
                            end
                        end
                    end

                    -- Combo Choice Box (Middle/Right)
                    if hasCombo and comboChoices and configComboKey then
                        local combo = vgui.Create("DComboBox", row)
                        combo:Dock(RIGHT)
                        combo:DockMargin(0, 0, 10, 0)
                        combo:SetWidth(100)
                        combo:SetFont("VEX_Menu_Normal")
                        combo:SetTextColor(Color(180, 180, 180))
                        combo.Paint = function(self, w, h)
                            surface.SetDrawColor(35, 35, 35, 255)
                            surface.DrawOutlinedRect(0, 0, w, h, 1)
                            surface.SetDrawColor(15, 15, 15, 255)
                            surface.DrawRect(1, 1, w - 2, h - 2)
                        end
                        for _, choice in ipairs(comboChoices) do
                            combo:AddChoice(choice)
                        end
                        combo:SetText(comboChoices[VEX.Config[configComboKey]] or comboChoices[1])
                        combo.OnSelect = function(_, index, value)
                            VEX.Config[configComboKey] = index
                        end
                    end

                    return row
                end

                local colsContainer = p:Add("DPanel")
                colsContainer:Dock(TOP)
                colsContainer:SetTall(580)
                colsContainer.Paint = function() end

                local leftCol = colsContainer:Add("DPanel")
                leftCol:Dock(LEFT)
                leftCol:SetWidth(410)
                leftCol.Paint = function() end

                local rightCol = colsContainer:Add("DPanel")
                rightCol:Dock(FILL)
                rightCol:DockMargin(15, 0, 0, 0)
                rightCol.Paint = function() end

                local leftScroll = vgui.Create("DScrollPanel", leftCol)
                leftScroll:Dock(FILL)
                leftScroll.Paint = function() end
                local sbar = leftScroll:GetVBar()
                if IsValid(sbar) then sbar:SetSize(0) end -- Make scrollbar invisible

                -- LEFT COLUMN SECTIONS
                -- 1. General Section
                local _, innerGen = CreateLeftPanelSection(leftScroll, "General", 200)
                CreateVEXConfigRow(innerGen, "Enable ESP Master", "esp_enabled", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerGen, "Draw Bounding Boxes", "esp_boxes", true, {"Full", "Corner", "3D"}, "esp_box_type", true, "esp_box_color")
                CreateVEXConfigRow(innerGen, "Draw Skeletons", "esp_skeleton", false, nil, nil, true, "esp_skeleton_color")
                CreateVEXConfigRow(innerGen, "Draw Player Names", "esp_names", false, nil, nil, true, "esp_name_color")
                CreateVEXConfigRow(innerGen, "Draw Health Bar", "esp_health", true, {"Bar", "Text"}, "esp_health_style", true, "esp_health_color")
                CreateVEXConfigRow(innerGen, "Draw Active Weapon", "esp_weapon", false, nil, nil, true, "esp_weapon_color")

                -- 2. Modifiers Section
                local _, innerMod = CreateLeftPanelSection(leftScroll, "Modifiers", 110)
                CreateVEXConfigRow(innerMod, "Show Team Members", "esp_show_team", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerMod, "Show Friends Only", "esp_show_friends", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerMod, "Render 3D Outlines", "esp_outline3d", false, nil, nil, false, nil)

                -- 3. Off-Screen Section
                local _, innerOff = CreateLeftPanelSection(leftScroll, "Off-Screen", 110)
                CreateVEXConfigRow(innerOff, "Off-Screen Indicators", "esp_offscreen", true, {"Arrow", "Triangle"}, "esp_offscreen_style", true, "esp_offscreen_color")
                CreateVEXSlider(innerOff, "Indicator Size", 5, 30, 0, "esp_offscreen_size")

                -- 4. Ignores Section
                local _, innerIgnore = CreateLeftPanelSection(leftScroll, "Ignores", 130)
                CreateVEXConfigRow(innerIgnore, "Ignore Team Members", "esp_ignore_team", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerIgnore, "Ignore Friends List", "esp_ignore_friends", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerIgnore, "Ignore Sleeper Players", "esp_ignore_sleepers", false, nil, nil, false, nil)
                CreateVEXConfigRow(innerIgnore, "Ignore NPCs & Entities", "esp_ignore_npcs", false, nil, nil, false, nil)

                local model -- Pre-declared to avoid Lua scoping issues in Paint callback
                
                -- RIGHT COLUMN SECTIONS
                -- 1. Preview Panel
                local previewPanel = rightCol:Add("DPanel")
                previewPanel:Dock(TOP)
                previewPanel:SetTall(380)
                previewPanel:DockMargin(0, 5, 0, 10)
                previewPanel.Paint = function(self, w, h)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(0, 0, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    draw.SimpleText("PREVIEW", "VEX_Menu_Bold", 15, 8, Color(120, 120, 140))
                end

                model = vgui.Create("DModelPanel", previewPanel)
                model:SetSize(280, 320)
                model:SetPos((330 - 280)/2, 40)
                
                local lp = LocalPlayer()
                local initialModel = "models/player/combine_super_soldier.mdl"
                if IsValid(lp) then
                    local pm = lp:GetNWString("playermodel")
                    if pm and pm ~= "" then
                        initialModel = player_manager.TranslatePlayerModel(pm) or lp:GetModel() or "models/player/combine_super_soldier.mdl"
                    else
                        initialModel = lp:GetModel() or "models/player/combine_super_soldier.mdl"
                    end
                end
                
                model:SetModel(initialModel)
                model.CurrentModelPath = initialModel
                
                local ent = model.Entity
                if IsValid(ent) then
                    ent:SetSkin(lp:GetSkin())
                    for _, bg in ipairs(lp:GetBodyGroups() or {}) do
                        ent:SetBodygroup(bg.id, lp:GetBodygroup(bg.id))
                    end
                end
                
                local isDragging = false
                local lastMouseX = 0
                local yawAngle = 0 -- Face the camera by default

                model.OnMousePressed = function(self, mouseCode)
                    if mouseCode == MOUSE_LEFT then
                        isDragging = true
                        lastMouseX = gui.MouseX()
                        self:MouseCapture(true)
                    end
                end

                model.OnMouseReleased = function(self, mouseCode)
                    if mouseCode == MOUSE_LEFT then
                        isDragging = false
                        self:MouseCapture(false)
                    end
                end

                model.Think = function(self)
                    if isDragging then
                        local curMouseX = gui.MouseX()
                        local delta = curMouseX - lastMouseX
                        yawAngle = yawAngle + delta * 0.5
                        lastMouseX = curMouseX
                    end
                    
                    local lp_think = LocalPlayer()
                    if IsValid(lp_think) then
                        local currentModel = "models/player/combine_super_soldier.mdl"
                        local pm = lp_think:GetNWString("playermodel")
                        if pm and pm ~= "" then
                            currentModel = player_manager.TranslatePlayerModel(pm) or lp_think:GetModel() or "models/player/combine_super_soldier.mdl"
                        else
                            currentModel = lp_think:GetModel() or "models/player/combine_super_soldier.mdl"
                        end
                        
                        local normCurrent = string.lower(currentModel):gsub("\\", "/")
                        local normCached = string.lower(self.CurrentModelPath or ""):gsub("\\", "/")
                        
                        if normCurrent ~= normCached then
                            self.CurrentModelPath = currentModel
                            self:SetModel(currentModel)
                            print("[VEX] Synchronized preview model to: " .. currentModel)
                        end
                        
                        local ent_think = self.Entity
                        if IsValid(ent_think) then
                            if ent_think:GetSkin() ~= lp_think:GetSkin() then
                                ent_think:SetSkin(lp_think:GetSkin())
                            end
                            for _, bg in ipairs(lp_think:GetBodyGroups() or {}) do
                                if ent_think:GetBodygroup(bg.id) ~= lp_think:GetBodygroup(bg.id) then
                                    ent_think:SetBodygroup(bg.id, lp_think:GetBodygroup(bg.id))
                                end
                            end
                        end
                    end
                end

                function model:LayoutEntity(Entity)
                    Entity:SetAngles(Angle(0, yawAngle, 0))
                    Entity:SetSequence(Entity:LookupSequence("walk_all"))
                    self:RunAnimation()
                end

                model:SetCamPos(Vector(90, 0, 36))
                model:SetLookAt(Vector(0, 0, 36))
                model:SetFOV(50)

                -- Draw active Chams effect on the model entity
                model.Paint = function(self, w, h)
                    if not IsValid(self.Entity) then return end
                    
                    local x, y = self:LocalToScreen(0, 0)
                    self:LayoutEntity(self.Entity)
                    
                    local ang = self.vLookatPos - self.vCamPos
                    
                    cam.Start3D(self.vCamPos, ang:Angle(), self.fFOV, x, y, w, h, 5, 4096)
                    cam.IgnoreZ(true)
                    
                    render.SuppressEngineLighting(true)
                    render.SetLightingOrigin(self.Entity:GetPos())
                    render.ResetModelLighting(self.colAmbientLight.r/255, self.colAmbientLight.g/255, self.colAmbientLight.b/255)
                    
                    for i=0, 6 do
                        local col = self.DirectionalLight[i]
                        if col then
                            render.SetModelLighting(i, col.r/255, col.g/255, col.b/255)
                        end
                    end
                    
                    if VEX.Config.chams_enabled and VEX.Config.chams_players then
                        local col = VEX.Config.chams_rgb and HSVToColor((RealTime() * 40) % 360, 1, 1) or VEX.Config.chams_player_color
                        local chams_materials_list = {
                            [1] = Material("models/wireframe"),
                            [2] = Material("models/debug/debugwhite"),
                            [3] = Material("models/shiny"),
                            [4] = Material("models/spawn_effect"),
                            [5] = Material("models/props_combine/combine_binocular01")
                        }
                        local matIdx = VEX.Config.chams_players_type or 1
                        local mat = chams_materials_list[matIdx]
                        
                        if mat then
                            render.MaterialOverride(mat)
                        end
                        render.SetColorModulation(col.r/255, col.g/255, col.b/255)
                        render.SetBlend(col.a and col.a/255 or 1)
                    end
                    
                    self.Entity:DrawModel()
                    
                    if VEX.Config.chams_enabled and VEX.Config.chams_players then
                        render.MaterialOverride()
                        render.SetColorModulation(1, 1, 1)
                        render.SetBlend(1)
                    end
                    
                    -- 1. Draw Bounding Box in DModelPanel Preview
                    if VEX.Config.esp_boxes then
                        local lp = LocalPlayer()
                        local boxCol = VEX.Config.esp_box_color or (IsValid(lp) and team.GetColor(lp:Team())) or Color(255, 255, 255)
                        
                        if VEX.Config.esp_box_type == 3 then
                            -- 3D Wireframe OBB Box
                            cam.IgnoreZ(true)
                            render.DrawWireframeBox(self.Entity:GetPos(), self.Entity:GetAngles(), self.Entity:OBBMins(), self.Entity:OBBMaxs(), boxCol, true)
                            cam.IgnoreZ(false)
                        else
                            local boxPos = self.Entity:GetPos() + Vector(0, 0, 36)
                            local faceAng = (self.vCamPos - boxPos):Angle()
                            local R = faceAng:Right()
                            local U = faceAng:Up()
                            
                            -- 16 units half-width, 36 units half-height
                            local tl = boxPos - R * 16 + U * 36
                            local tr = boxPos + R * 16 + U * 36
                            local bl = boxPos - R * 16 - U * 36
                            local br = boxPos + R * 16 - U * 36
                            
                            cam.IgnoreZ(true)
                            render.SetMaterial(Material("vgui/white"))
                            if VEX.Config.esp_box_type == 2 then
                                -- Corner Box
                                local lenH = 16 * 2 * 0.25
                                local lenV = 36 * 2 * 0.25
                                
                                render.DrawBeam(tl, tl + R * lenH, 0.4, 0, 1, boxCol)
                                render.DrawBeam(tl, tl - U * lenV, 0.4, 0, 1, boxCol)
                                
                                render.DrawBeam(tr, tr - R * lenH, 0.4, 0, 1, boxCol)
                                render.DrawBeam(tr, tr - U * lenV, 0.4, 0, 1, boxCol)
                                
                                render.DrawBeam(bl, bl + R * lenH, 0.4, 0, 1, boxCol)
                                render.DrawBeam(bl, bl + U * lenV, 0.4, 0, 1, boxCol)
                                
                                render.DrawBeam(br, br - R * lenH, 0.4, 0, 1, boxCol)
                                render.DrawBeam(br, br + U * lenV, 0.4, 0, 1, boxCol)
                            else
                                -- Full Box
                                render.DrawBeam(tl, tr, 0.4, 0, 1, boxCol)
                                render.DrawBeam(tr, br, 0.4, 0, 1, boxCol)
                                render.DrawBeam(br, bl, 0.4, 0, 1, boxCol)
                                render.DrawBeam(bl, tl, 0.4, 0, 1, boxCol)
                            end
                            cam.IgnoreZ(false)
                        end
                    end

                    -- 2. Draw 3D Skeleton (X-Ray sorted by hierarchy order)
                    if VEX.Config.esp_skeleton then
                        local skeletonColor = VEX.Config.esp_skeleton_color or Color(255, 255, 255, 220)
                        self.Entity:SetupBones()
                        
                        local bones = GetSkeletonBones(self.Entity)
                        cam.IgnoreZ(true)
                        render.SetMaterial(Material("vgui/white"))
                        for _, pair in ipairs(bones) do
                            local p1 = GetEntityBonePosition(self.Entity, pair[1], true)
                            local p2 = GetEntityBonePosition(self.Entity, pair[2], true)
                            if p1 and p2 and p1 ~= self.Entity:GetPos() and p2 ~= self.Entity:GetPos() then
                                render.DrawBeam(p1, p2, 0.4, 0, 1, skeletonColor)
                            end
                        end
                        cam.IgnoreZ(false)
                    end

                    local camPos = self:GetCamPos()
                    local lookAt = self:GetLookAt()
                    local camAngles = (camPos - lookAt):Angle()
                    local textAngles = Angle(0, camAngles.y - 90, 90)

                    -- 3. Draw Health Bar in 3D (vertical beam)
                    if VEX.Config.esp_health and (VEX.Config.esp_health_style or 1) ~= 2 then
                        local lp = LocalPlayer()
                        local hp = 100
                        local maxHp = 100
                        if IsValid(lp) then
                            hp = lp:Health()
                            maxHp = lp:GetMaxHealth() or 100
                        end
                        local hpPercent = math.Clamp(hp / maxHp, 0, 1)
                        local hpColor = VEX.Config.esp_health_color or Color((1 - hpPercent) * 255, hpPercent * 255, 0, 255)
                        hpColor = Color(hpColor.r, hpColor.g, hpColor.b, 255)
                        
                        local hMins, hMaxs = self.Entity:OBBMins(), self.Entity:OBBMaxs()
                        
                        local leftOffset = camAngles:Right()
                        local bottomHealth = self.Entity:GetPos() + leftOffset * 20
                        local topHealth = bottomHealth + Vector(0, 0, hMaxs.z)
                        local healthPos = bottomHealth + Vector(0, 0, hMaxs.z * hpPercent)
                        
                        cam.IgnoreZ(true)
                        render.SetMaterial(Material("vgui/white"))
                        render.SuppressEngineLighting(true)
                        
                        -- Background beam
                        render.DrawBeam(bottomHealth, topHealth, 1.2, 0, 1, Color(0, 0, 0, 180))
                        -- Health gauge beam
                        if hpPercent > 0 then
                            render.DrawBeam(bottomHealth, healthPos, 0.8, 0, 1, hpColor)
                        end
                        
                        render.SuppressEngineLighting(false)
                        cam.IgnoreZ(false)
                    end

                    render.SuppressEngineLighting(false)
                    cam.IgnoreZ(false)
                    cam.End3D()
                    
                    self.LastPaint = RealTime()
                end

                model.PaintOver = function(self, w, h)
                    -- Draw ESP texts here in 2D on top of the panel
                    if VEX.Config.esp_names then
                        local nameText = "Player"
                        local lp = LocalPlayer()
                        if IsValid(lp) then nameText = lp:Nick() end
                        local nameColor = VEX.Config.esp_name_color or Color(255, 255, 255, 255)
                        nameColor = Color(nameColor.r, nameColor.g, nameColor.b, 255)
                        draw.SimpleText(nameText, "DermaDefault", w / 2, 15, nameColor, TEXT_ALIGN_CENTER)
                    end

                    if VEX.Config.esp_health and (VEX.Config.esp_health_style or 1) == 2 then
                        local lp = LocalPlayer()
                        local hp = 100
                        if IsValid(lp) then
                            hp = lp:Health()
                        end
                        local hpPercent = math.Clamp(hp / 100, 0, 1)
                        local hpColor = VEX.Config.esp_health_color or Color((1 - hpPercent) * 255, hpPercent * 255, 0, 255)
                        hpColor = Color(hpColor.r, hpColor.g, hpColor.b, 255)
                        
                        local camPos = self:GetCamPos()
                        local lookAt = self:GetLookAt()
                        local camAngles = (camPos - lookAt):Angle()
                        local leftOffset = camAngles:Right()
                        local hMins, hMaxs = self.Entity:OBBMins(), self.Entity:OBBMaxs()
                        
                        local textPos3D = self.Entity:GetPos() - leftOffset * 20 + Vector(0, 0, hMaxs.z / 2)
                        local px, py = Project3DTo2D(self, textPos3D, w, h)
                        if px and py then
                            draw.SimpleText(tostring(hp) .. " HP", "DermaDefault", px, py, hpColor, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
                        end
                    end

                    if VEX.Config.esp_weapon then
                        local lp = LocalPlayer()
                        local wepName = "None"
                        if IsValid(lp) then
                            local wep = lp:GetActiveWeapon()
                            if IsValid(wep) then
                                wepName = wep:GetPrintName() or wep:GetClass() or "None"
                            end
                        end
                        local weaponColor = VEX.Config.esp_weapon_color or Color(220, 220, 220, 255)
                        weaponColor = Color(weaponColor.r, weaponColor.g, weaponColor.b, 255)
                        draw.SimpleText(wepName, "DermaDefault", w / 2, h - 30, weaponColor, TEXT_ALIGN_CENTER)
                    end
                end

                -- 2. Chams Settings Panel
                local chamsPanel = rightCol:Add("DPanel")
                chamsPanel:Dock(FILL)
                chamsPanel:DockMargin(0, 0, 0, 10)
                chamsPanel.Paint = function(self, w, h)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(0, 0, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    draw.SimpleText("CHAMS SETTINGS", "VEX_Menu_Bold", 15, 8, Color(120, 120, 140))
                end

                local chamsScroll = vgui.Create("DScrollPanel", chamsPanel)
                chamsScroll:Dock(FILL)
                chamsScroll:DockMargin(2, 25, 2, 2)
                local sbarChams = chamsScroll:GetVBar()
                if IsValid(sbarChams) then sbarChams:SetSize(0) end -- Make scrollbar invisible

                CreateVEXConfigRow(chamsScroll, "Enable Chams Master", "chams_enabled", false, nil, nil, false, nil)
                CreateVEXConfigRow(chamsScroll, "Rainbow RGB Accent", "chams_rgb", false, nil, nil, false, nil)

                local chamsTypes = {"Wireframe", "Flat Solid", "Metallic", "Glow Overlay", "Glass Semitrans"}
                CreateVEXConfigRow(chamsScroll, "Players Chams", "chams_players", true, chamsTypes, "chams_players_type", true, "chams_player_color")
                CreateVEXConfigRow(chamsScroll, "Hands Chams", "chams_self", true, chamsTypes, "chams_self_type", true, "chams_self_color")
                CreateVEXConfigRow(chamsScroll, "Weapon Chams", "chams_weapon", true, chamsTypes, "chams_weapon_type", true, "chams_weapon_color")
            end
        },
        {
            name = "Movement",
            icon = "✈",
            create = function(p)
                local secMove, innerMove = CreateVEXSection(p, "Movement Mechanics")
                secMove:SetTall(120)

                CreateVEXCheckBox(innerMove, "Bunnyhop (Auto-Jump)", "move_bhop")
                CreateVEXCheckBox(innerMove, "Auto-Strafe", "move_strafe")
            end
        },
        {
            name = "Visuals",
            icon = "⚙",
            create = function(p)
                local colsContainer = p:Add("DPanel")
                colsContainer:Dock(TOP)
                colsContainer:SetTall(420)
                colsContainer.Paint = function() end

                local leftCol = colsContainer:Add("DPanel")
                leftCol:Dock(LEFT)
                leftCol:SetWidth(370)
                leftCol.Paint = function() end

                local rightCol = colsContainer:Add("DPanel")
                rightCol:Dock(FILL)
                rightCol:DockMargin(10, 0, 0, 0)
                rightCol.Paint = function() end

                -- Left Column Section 1: Camera Controls
                local secCam, innerCam = CreateVEXSection(leftCol, "Camera Controls")
                secCam:SetTall(220)

                CreateVEXCheckBox(innerCam, "Thirdperson Cam", "vis_thirdperson")
                CreateVEXCheckBox(innerCam, "Freecam (WSAD + Mouse)", "vis_freecam")

                CreateVEXSlider(innerCam, "Camera FOV", 30, 160, 0, "vis_fov")
                CreateVEXSlider(innerCam, "Weapon FOV", 30, 160, 0, "vis_wfov")

                -- Left Column Section 2: Menu Customization
                local secFont, innerFont = CreateVEXSection(leftCol, "Menu Customization")
                secFont:SetTall(160)

                local lblFontFamily = innerFont:Add("DLabel")
                lblFontFamily:SetText("Font Family:")
                lblFontFamily:SetFont("VEX_Menu_Normal")
                lblFontFamily:SetTextColor(Color(180, 180, 180))
                lblFontFamily:Dock(TOP)
                lblFontFamily:DockMargin(12, 4, 10, 2)

                local comboFont = innerFont:Add("DComboBox")
                comboFont:Dock(TOP)
                comboFont:DockMargin(12, 2, 20, 10)
                comboFont:SetFont("VEX_Menu_Normal")
                comboFont:SetTextColor(Color(180, 180, 180))
                comboFont.Paint = function(self, w, h)
                    surface.SetDrawColor(35, 35, 35, 255)
                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                    surface.SetDrawColor(15, 15, 15, 255)
                    surface.DrawRect(1, 1, w - 2, h - 2)
                end
                
                local fonts = { "Segoe UI", "Arial", "Tahoma", "Verdana", "Trebuchet MS", "Consolas", "Roboto" }
                for _, fName in ipairs(fonts) do
                    comboFont:AddChoice(fName)
                end
                comboFont:SetText(VEX.Config.vis_menu_font or "Consolas")
                comboFont.OnSelect = function(_, index, value)
                    VEX.Config.vis_menu_font = value
                    VEX.UpdateMenuFont()
                    VEX.RebuildMenu()
                end

                local sliderFontSize = CreateVEXSlider(innerFont, "Font Size", 10, 24, 0, "vis_menu_fontsize")
                sliderFontSize.OnValueChanged = function(_, val)
                    local newVal = math.Round(val)
                    if VEX.Config.vis_menu_fontsize ~= newVal then
                        VEX.Config.vis_menu_fontsize = newVal
                        timer.Create("VEX_FontRebuild_Debounce", 0.15, 1, function()
                            VEX.UpdateMenuFont()
                            VEX.RebuildMenu()
                        end)
                    end
                end

                -- Right Column Section 1: Viewmodel Offsets
                local secVM, innerVM = CreateVEXSection(rightCol, "Viewmodel Offsets")
                secVM:SetTall(220)

                CreateVEXSlider(innerVM, "Offset X (Side)", -30, 30, 1, "vis_vm_x")
                CreateVEXSlider(innerVM, "Offset Y (Forward)", -30, 30, 1, "vis_vm_y")
                CreateVEXSlider(innerVM, "Offset Z (Up)", -30, 30, 1, "vis_vm_z")
            end
        },
        {
            name = "Online",
            icon = "👥",
            create = function(p)
                local secList, innerList = CreateVEXSection(p, "Online Player List")
                secList:SetTall(300)

                local listContainer = innerList:Add("DPanel")
                listContainer:Dock(TOP)
                listContainer.Paint = function() end

                local lastFingerprint = ""

                listContainer.Think = function(self)
                    local plys = player.GetAll()
                    local fp = tostring(#plys)
                    for _, ply in ipairs(plys) do
                        if IsValid(ply) then
                            fp = fp .. "_" .. ply:UserID() .. "_" .. ply:Nick() .. "_" .. (VEX.SpectateTarget == ply and "1" or "0")
                        end
                    end

                    if fp ~= lastFingerprint then
                        lastFingerprint = fp
                        self:Clear()

                        local validCount = 0
                        for _, ply in ipairs(plys) do
                            if not IsValid(ply) then continue end
                            validCount = validCount + 1

                            local row = vgui.Create("DPanel", self)
                            row:Dock(TOP)
                            row:SetTall(44)
                            row:DockMargin(12, 2, 15, 2)
                            row.Paint = function(s, w, h)
                                surface.SetDrawColor(20, 20, 25, 255)
                                surface.DrawRect(0, 0, w, h)
                                surface.SetDrawColor(35, 35, 35, 255)
                                surface.DrawOutlinedRect(0, 0, w, h, 1)
                            end

                            local avatar = vgui.Create("AvatarImage", row)
                            avatar:SetSize(32, 32)
                            avatar:Dock(LEFT)
                            avatar:DockMargin(6, 6, 6, 6)
                            avatar:SetPlayer(ply, 32)

                            local name = vgui.Create("DLabel", row)
                            name:Dock(FILL)
                            name:DockMargin(10, 0, 10, 0)
                            name:SetText(ply:Nick())
                            name:SetFont("VEX_Menu_Bold")
                            name:SetTextColor(team.GetColor(ply:Team()) or Color(255, 255, 255))

                            if ply ~= LocalPlayer() then
                                -- Steal Outfit Button
                                local btnSteal = vgui.Create("DButton", row)
                                btnSteal:SetSize(90, 24)
                                btnSteal:Dock(RIGHT)
                                btnSteal:DockMargin(5, 10, 10, 10)
                                btnSteal:SetText("Steal Outfit")
                                btnSteal:SetFont("VEX_Menu_Normal")
                                btnSteal:SetTextColor(Color(180, 180, 180))
                                btnSteal.Paint = function(s, w, h)
                                    local hovered = s:IsHovered()
                                    surface.SetDrawColor(35, 35, 35, 255)
                                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                                    surface.SetDrawColor(hovered and 220 or 15, hovered and 0 or 15, hovered and 255 or 15, 255)
                                    surface.DrawRect(1, 1, w - 2, h - 2)
                                end
                                btnSteal.DoClick = function()
                                    local model = ply:GetModel()
                                    local skin = ply:GetSkin()
                                    if model then
                                        LocalPlayer():SetModel(model)
                                        LocalPlayer():SetSkin(skin)
                                        for i = 0, ply:GetNumBodyGroups() - 1 do
                                            local bg = ply:GetBodygroup(i)
                                            LocalPlayer():SetBodygroup(i, bg)
                                        end
                                        surface.PlaySound("buttons/button14.wav")
                                        chat.AddText(Color(220, 0, 255), "[VEX] ", Color(255, 255, 255), "Stole outfit from ", team.GetColor(ply:Team()), ply:Nick())
                                    end
                                end

                                -- Spectate Button
                                local btnSpec = vgui.Create("DButton", row)
                                btnSpec:SetSize(90, 24)
                                btnSpec:Dock(RIGHT)
                                btnSpec:DockMargin(5, 10, 5, 10)
                                btnSpec:SetFont("VEX_Menu_Normal")
                                
                                local isSpec = (VEX.SpectateTarget == ply)
                                btnSpec:SetText(isSpec and "Spectating" or "Spectate")
                                btnSpec:SetTextColor(isSpec and Color(255, 255, 255) or Color(180, 180, 180))
                                btnSpec.Paint = function(s, w, h)
                                    local active = (VEX.SpectateTarget == ply)
                                    local hovered = s:IsHovered()
                                    local col = active and Color(46, 204, 113, 255) or (hovered and Color(220, 0, 255, 255) or Color(40, 40, 50, 255))
                                    surface.SetDrawColor(35, 35, 35, 255)
                                    surface.DrawOutlinedRect(0, 0, w, h, 1)
                                    surface.SetDrawColor(col)
                                    surface.DrawRect(1, 1, w - 2, h - 2)
                                end
                                btnSpec.DoClick = function()
                                    if VEX.SpectateTarget == ply then
                                        VEX.SpectateTarget = nil
                                    else
                                        VEX.SpectateTarget = ply
                                    end
                                    surface.PlaySound("buttons/lightswitch2.wav")
                                end
                            else
                                local lblYou = vgui.Create("DLabel", row)
                                lblYou:Dock(RIGHT)
                                lblYou:DockMargin(0, 0, 20, 0)
                                lblYou:SetText("(You)")
                                lblYou:SetFont("VEX_Menu_Normal")
                                lblYou:SetTextColor(Color(120, 120, 140))
                                lblYou:SizeToContents()
                            end
                        end
                        self:SetTall(validCount * 48)
                        secList:SetTall(validCount * 48 + 32)
                        self:InvalidateLayout(true)
                        p:InvalidateLayout(true)
                    end
                end
            end
        }
    }

    -- Rebuild function helper
    function VEX.RebuildMenu()
        if IsValid(VEX.MenuFrame) then
            local px, py = VEX.MenuFrame:GetPos()
            VEX.MenuFrame:Remove()
            CreateVEXMenu()
            if IsValid(VEX.MenuFrame) then
                VEX.MenuFrame:SetPos(px, py)
            end
        end
    end

    -- Create top horizontal tab container
    local tabContainer = vgui.Create("DPanel", topbar)
    tabContainer:SetSize(800 - 180, 80)
    tabContainer:SetPos(180, 0)
    tabContainer.Paint = function() end
    tabContainer.OnMousePressed = StartDrag
    tabContainer.OnMouseReleased = EndDrag

    if VEX.ActiveTabIdx and (VEX.ActiveTabIdx < 1 or VEX.ActiveTabIdx > #tabs) then
        VEX.ActiveTabIdx = 1
    end

    -- Create topbar buttons
    local buttonWidth = math.floor((800 - 180) / #tabs)
    for index, tab in ipairs(tabs) do
        local btn = vgui.Create("DButton", tabContainer)
        btn:SetSize(buttonWidth, 80)
        btn:SetPos((index - 1) * buttonWidth, 0)
        btn:SetText("")
        
        btn.Paint = function(self, w, h)
            local active = (VEX.ActiveTabIdx == index)
            local hover = self:IsHovered()
            
            if active then
                if index == #tabs then
                    draw.RoundedBoxEx(8, 0, 0, w, h, Color(18, 18, 22, 255), false, true, false, false)
                else
                    draw.RoundedBox(0, 0, 0, w, h, Color(18, 18, 22, 255))
                end
                -- Bottom accent indicator
                draw.RoundedBox(0, 0, h - 4, w, 4, accentColor)
            elseif hover then
                if index == #tabs then
                    draw.RoundedBoxEx(8, 0, 0, w, h, Color(12, 12, 14, 255), false, true, false, false)
                else
                    draw.RoundedBox(0, 0, 0, w, h, Color(12, 12, 14, 255))
                end
            end

            local textCol = active and Color(255, 255, 255) or (hover and Color(220, 220, 220) or Color(150, 150, 160))
            
            -- Draw large centered icon
            draw.SimpleText(tab.icon, "VEX_Menu_Icon", w / 2, 18, textCol, TEXT_ALIGN_CENTER)
            
            -- Draw small centered text below icon
            draw.SimpleText(tab.name, "VEX_Menu_Normal", w / 2, 48, textCol, TEXT_ALIGN_CENTER)
        end

        btn.DoClick = function()
            VEX.ActiveTabIdx = index
            ShowPanel(tab.create)
        end

        -- Initialize active panel
        if index == (VEX.ActiveTabIdx or 1) then
            VEX.ActiveTabIdx = index
            ShowPanel(tab.create)
        end
    end

    VEX.MenuFrame = f
end


concommand.Add("vex_menu", function()
    surface.PlaySound("buttons/lightswitch2.wav")
    if IsValid(VEX.MenuFrame) then
        VEX.MenuFrame:Remove()
        VEX.MenuFrame = nil
    else
        CreateVEXMenu()
    end
end)

print("[VEX] Pure GLua Cheat Loaded Successfully!")
print("[VEX] Press DELETE or INSERT to open the premium Derma Menu, or type 'vex_menu' in console.")
