--// CodingAgent 2026

local Modules = script.Parent
local Libs = script.Parent.Parent.Libraries

local Utilities = require(Modules.Utilities)
local Frontend = require(Modules.Frontend)
local Var = require(Modules.Variables)

local Admins = {}
local Connections: { RBXScriptConnection } = {}

local RanksFrame = Var.MainFrame.Configuration.Admins.Container.Ranks.Content
local Frames = Var.MainFrame.Configuration.Admins.NewAdmin

local TweenService = Var.Services.TweenService

local CreatorStepCount = "6"

local function NewCard(RankData: { any }, ParentFrame, IsDummyCard)
	local Template = RanksFrame.Template:Clone()
	local CreatorName = RankData.CreatorID == 1 and Utilities.Translate("admin.ranktype.System")
		or Var.Services.Players:GetNameFromUserIdAsync(RankData.CreatorID)

	Template.Name = RankData.Name
	Template.RankName.Text = RankData.Name
	Template.Info.Text = string.format(
		Utilities.Translate("Configuration.Admins.Container.Ranks.Content.Template.Info"),
		RankData.RankID,
		RankData.Apps.SuperAdmin and Utilities.Translate("Configuration.Admins.Ranks.HasSuperAdmin")
			or string.format(Utilities.Translate("Configuration.Admins.Ranks.HasApps"), #RankData.Apps),
		CreatorName,
		Utilities.FormatRelativeTime(RankData.Modified)
	)

	if RankData.Apps.SuperAdmin then
		local Card = Template.Pages.Frame:Clone()
		local Tip = Instance.new("TextButton")

		Card.Visible = true
		Card.AppName.Text = Utilities.Translate("admin.ranks.superadmin.Detail")
		Card.ImageLabel.Image = Utilities.Icon("user-shield")
		Card.Parent = Template.Pages

		Tip.Size = UDim2.new(1, 0, 1, 0)
		Tip.BackgroundTransparency = 1
		Tip.BorderSizePixel = 0
		Tip.Parent = Card
		Tip.Text = ""

		table.insert(
			Connections,
			Tip.MouseButton1Click:Connect(function()
				Frontend.Popup.new(
					{
						Icon = Utilities.Icon("administer"),
						Name = "Administer",
						Subheader = "Information",
					},
					{
						Primary = Utilities.Icon("user-shield"),
					},
					Utilities.Translate("admin.ranks.superadmin.Detail"),
					Utilities.Translate("admin.ranks.superadmin.Body"),
					{
						{
							Text = Utilities.Translate("generic.Done"),
							Icon = Utilities.Icon("check-plain"),
							Callback = function(c)
								c()
							end,
						},
					}
				)
			end)
		)
	end

	local UsableAppInfo = {}
	local AppCount = 0

	for App, IsVisible in RankData.Apps do
		if App == "CachedData" or App == "AdmHomepage" or App == "SuperAdmin" then
			continue
		end

		if IsVisible then
			AppCount += 1
			table.insert(UsableAppInfo, RankData.Apps.CachedData[App])
		end
	end

	if AppCount > 6 then
		for j = 1, 5 do
			if type(RankData.Apps[j]) == "boolean" then
				continue
			end

			local Card = Template.Pages.Frame:Clone()

			Card.Visible = true
			Card.AppName.Text = UsableAppInfo[j].Name
			Card.ImageLabel.Image = UsableAppInfo[j].Icon
			Card.Parent = Template.Pages
		end

		local Card = Template.Pages.Frame:Clone()
		Card.Visible = true
		Card.AppName.Text = string.format(Utilities.Translate("admin.ranks.Others"), AppCount - 5)
		Card.Parent = Template.Pages
	else
		for k, App in UsableAppInfo do
			if type(App) == "boolean" then
				continue
			end

			local Card = Template.Pages.Frame:Clone()

			Card.Visible = true
			Card.AppName.Text = App.Name
			Card.ImageLabel.Image = App.Icon
			Card.Parent = Template.Pages
		end
	end

	xpcall(function()
		Template.ColorBG.BackgroundColor3 = Color3.fromHex(RankData.Color)
	end, function()
		Template.ColorBG.BackgroundColor3 = Color3.new(0.239, 0.643, 1)
	end)

	Template.Parent = ParentFrame
	Template.Visible = true

	local UserNames = {}
	local MoveTI = TweenInfo.new(Var.AnimationSpeed * 0.3)

	for i = 1, 3 do
		local User = RankData.Members[i]

		if User == nil then
			break
		end
		if User.MemberType == "User" then
			xpcall(function()
				Template.ProfilePictures[i].Visible = true
				Template.ProfilePictures[i].Image = Var.Services.Players:GetUserThumbnailAsync(
					User.ID,
					Enum.ThumbnailType.HeadShot,
					Enum.ThumbnailSize.Size100x100
				)

				table.insert(UserNames, Var.Services.Players:GetNameFromUserIdAsync(User.ID))
			end, function(e)
				Utilities.Logging.Warn(e)
				Template.ProfilePictures[i].Image = Utilities.Icon("tear")
			end)
		else
			local Success, GroupInfo = pcall(function()
				return game:GetService("GroupService"):GetGroupInfoAsync(User.ID)
			end)

			if Success then
				Template.ProfilePictures[i].Image = GroupInfo.EmblemUrl
				Template.ProfilePictures[i].Visible = true

				Template.ProfilePictures[i].UICorner.CornerRadius = UDim.new(0, 5)

				table.insert(UserNames, GroupInfo.Name)
			end
		end
	end

	if UserNames[1] == nil then
		Template.MembersText.Text =
			string.format(Utilities.Translate("admin.ranks.members.one"), Utilities.Translate("generic.User"))

		return Template
	end

	Template.MembersText.Text = (
		#UserNames == 3
			and string.format(
				"%s, %s, %s, and %d %s",
				UserNames[1],
				UserNames[2],
				UserNames[3],
				#RankData.Members - 3,
				Utilities.Translate(
					#RankData.Members - 3 == 1 and "admin.ranks.members.one" or "admin.ranks.members.more"
				)
					:format(#RankData.Members - 3)
			)
		or #UserNames == 2 and string.format(
			"%s and %s %s",
			UserNames[1],
			UserNames[2],
			Utilities.Translate("admin.ranks.members.two")
		)
		or string.format("%s %s", UserNames[1], Utilities.Translate("admin.ranks.members.one"))
	)

	if IsDummyCard then
		return Template
	end

	table.insert(
		Connections,
		Template.EditTrigger.MouseEnter:Connect(function()
			if Var.RankCreatorOpen then
				return
			end

			Var.Services.TweenService
				:Create(Template.RankName, MoveTI, {
					Position = UDim2.fromScale(0.1, 0.036),
					Size = UDim2.fromScale(0.858, 0.126),
				})
				:Play()

			Var.Services.TweenService
				:Create(Template.Configure, MoveTI, {
					ImageTransparency = 0,
				})
				:Play()
		end)
	)

	table.insert(
		Connections,
		Template.EditTrigger.MouseLeave:Connect(function()
			Var.Services.TweenService
				:Create(Template.RankName, MoveTI, {
					Position = UDim2.fromScale(0.025, 0.036),
					Size = UDim2.fromScale(0.955, 0.126),
				})
				:Play()

			Var.Services.TweenService
				:Create(Template.Configure, MoveTI, {
					ImageTransparency = 1,
				})
				:Play()
		end)
	)

	if RankData.Protected then
		Template.Configure.Image = Utilities.Icon("lock")

		table.insert(
			Connections,
			Template.EditTrigger.MouseButton1Click:Connect(function()
				if Var.RankCreatorOpen then
					return
				end

				Frontend.Toast({
					Icon = Utilities.Icon("triangle-warning"),
					Text = Utilities.Translate("admin.ranks.protected.Detail"),
					Subtext = Utilities.Translate("admin.ranks.protected.Body"),
					Timeout = 5,
				})
			end)
		)
	else
		local Env = require(script.Parent.UI.AdminHelperEnv)

		table.insert(
			Connections,
			Template.EditTrigger.MouseButton1Click:Connect(function()
				if Var.RankCreatorOpen then
					Frontend.Toast({
						Icon = Utilities.Icon("triangle-warning"),
						Text = Utilities.Translate("editrank.disabled.creatoropen.Header"),
						Subtext = Utilities.Translate("editrank.disabled.creatoropen.Body"),
						Timeout = 5,
					})

					return
				end

				Env.EditMode = true
				Env.EditModeMembers = RankData.Members
				Env.EditModeApps = RankData.Apps
				Env.EditModeName = RankData.Name
				Env.EditModeColor = RankData.Color

				Admins.OpenCreator()
			end)
		)
	end

	return Template
end

function Admins.Load(): ()
	for _, Item in RanksFrame:GetChildren() do
		if Item:IsA("Frame") and Item.Name ~= "Template" then
			Item:Destroy()
		end
	end

	for _, Connection in Connections do
		Connection:Disconnect()
	end

	Connections = {}

	local Shimmer1 = require(Libs.Shime).new(Var.MainFrame.Configuration.Admins.Container.Ranks)

	Shimmer1:Play()

	task.defer(function()
		local List

		xpcall(function()
			List = Var.Remotes.GetRanks:InvokeServer()
		end, function(e)
			Frontend.Popup.new(
				{
					Icon = Utilities.Icon("administer"),
					Name = "Access Control",
					Subheader = "Error",
				},
				{
					Primary = Utilities.Icon("user"),
					SubIcon = Utilities.Icon("triangle-warning"),
				},
				Utilities.Translate("admin.rankcreator.corrupt.Detail"),
				string.format(Utilities.Translate("admin.rankcreator.corrupt.Body"), e)({
					{
						Text = "Ok",
						Icon = Utilities.Icon("check-plain"),
						Callback = function(c)
							c()
						end,
					},
				})
			)

			List = {}
		end)

		if typeof(List) == "string" then
			Utilities.Logging.Warn(`Failed: {List}`)

			return "Something went wrong"
		else
			for i, v in List do
				NewCard(v, RanksFrame, false)
			end
		end

		Shimmer1:Pause()
		Shimmer1:GetFrame():Destroy()
	end)
end

local Page = 1

local function SwapPages(Page1, Page2, NewIcon, Spin, PageNumber)
	if type(Spin) == "number" then
		PageNumber = Spin
	end

	Page = PageNumber
	local TTC = Var.AnimationSpeed * 0.4

	local Tweem = TweenService:Create(
		Page1,
		TweenInfo.new(TTC * 1.3, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(-0.5, 0, 0, 0), GroupTransparency = 1 }
	)

	Tweem:Play()
	TweenService:Create(
		Frames.SideDecor.ImageLabel,
		TweenInfo.new(TTC, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(0, 0, 0.5, 0), ImageTransparency = 1 }
	):Play()
	TweenService:Create(
		Frames.SideDecor.AdmSpinner,
		TweenInfo.new(TTC, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(0, 0, 0.5, 0), GroupTransparency = 1 }
	):Play()

	Tweem.Completed:Wait()

	Page2.Position = UDim2.new(0.3, 0, 0, 0)
	Page2.GroupTransparency = 1

	Frames.SideDecor.ImageLabel.Position = UDim2.new(0.8, 0, 0.5, 0)
	Frames.SideDecor.AdmSpinner.Position = UDim2.new(0.8, 0, 0.5, 0)

	Frames.SideDecor.AdmSpinner.Visible = Spin
	Frames.SideDecor.ImageLabel.Image = NewIcon
	Frames.SideDecor.ImageLabel.Visible = not Spin

	Page2.Visible = true
	Page1.Visible = false

	local ET = TweenService:Create(
		Page2,
		TweenInfo.new(TTC * 1.2, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(0, 0, 0, 0), GroupTransparency = 0 }
	)
	TweenService:Create(
		Frames.SideDecor.ImageLabel,
		TweenInfo.new(TTC, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(0.5, 0, 0.5, 0), ImageTransparency = 0 }
	):Play()
	TweenService:Create(
		Frames.SideDecor.AdmSpinner,
		TweenInfo.new(TTC, Enum.EasingStyle.Cubic),
		{ Position = UDim2.new(0.5, 0, 0.5, 0), GroupTransparency = 0 }
	):Play()

	ET:Play()

	local Dots = Frames.BottomData.Controls.Dots

	for i, Dot in Dots:GetChildren() do
		if not Dot:IsA("Frame") then
			continue
		end
		Dot.UIStroke.Thickness = 0
		Dot.UIStroke.Color = Color3.fromRGB(37, 72, 194)

		Dot.BackgroundColor3 = Color3.fromRGB(180, 180, 180)
	end

	Dots[`Dot{PageNumber}`].UIStroke.Thickness = 2
	Dots[`Dot{PageNumber}`].BackgroundColor3 = Color3.fromRGB(37, 72, 194)
	Dots.AProgress.Text =
		string.format(Utilities.Translate("Configuration.Admins.NewAdmin.BottomData.StepLabel"), Page, CreatorStepCount)

	ET.Completed:Wait()
end

function Admins.ClearEditState(Env)
	if Env.EditMode == true then
		Env.EditMode = false
		Env.EditModeMembers = {}
		Env.EditModeApps = {}
		Env.EditModeName = ""
		Env.EditModeColor = ""
		Env.EditModeIsProtected = false
		Env.EditModeRank = 0
	end

	Env.Apps = {}
end

function Admins.GetEditState()
	local Clone = table.clone(require(script.Parent.UI.AdminHelperEnv))

	Clone.Strings = nil

	return Clone
end

function Admins.OpenCreator()
	local NewAdmin = Var.MainFrame.Configuration.Admins.NewAdmin
	local CompleteTime = Var.AnimationSpeed * 0.6

	NewAdmin.GroupTransparency = 1
	NewAdmin.Size = UDim2.fromScale(0.6, 0.57)
	NewAdmin.Position = UDim2.fromScale(0.5, 0.65)

	Var.Services.TweenService
		:Create(NewAdmin, TweenInfo.new(CompleteTime, Enum.EasingStyle.Quart), {
			Size = UDim2.fromScale(0.867, 0.847),
			Position = UDim2.fromScale(0.5, 0.5),
			GroupTransparency = 0,
		})
		:Play()

	NewAdmin.Visible = true
	Var.RankCreatorOpen = true
end

function Admins.CloseCreator()
	local NewAdmin = Var.MainFrame.Configuration.Admins.NewAdmin
	local CompleteTime = Var.AnimationSpeed * 0.5

	Var.Services.TweenService
		:Create(NewAdmin, TweenInfo.new(CompleteTime, Enum.EasingStyle.Quart), {
			Size = UDim2.fromScale(0.6, 0.57),
			Position = UDim2.fromScale(0.5, 0.65),
			GroupTransparency = 1,
		})
		:Play()

	task.delay(CompleteTime, function()
		Var.RankCreatorOpen = false
		Var.MainFrame.Configuration.Admins.NewAdmin.Visible = false

		if Page == 2 then
			SwapPages(Frames.Page2, Frames.Page1, "rbxassetid://18151072839", false, 1)
		elseif Page == 3 then
			SwapPages(Frames.Page3, Frames.Page1, "rbxassetid://18151072839", false, 1)
		elseif Page == 4 then
			SwapPages(Frames.Page4, Frames.Page1, "rbxassetid://18151072839", false, 1)
		elseif Page == 5 then
			SwapPages(Frames.Page6, Frames.Page1, "rbxassetid://18151072839", false, 1)
		end
	end)
end

function Admins.RunCreatorApp()
	local CanGoBack = true
	local Env = require(script.Parent.UI.AdminHelperEnv)
	local Dots = Frames.BottomData.Controls.Dots

	local ConnectionsTable
	local FinalData = {}

	Frames.BottomData.RankTitle.Text = Utilities.Translate("Configuration.Admins.NewAdmin.BottomData.RankTitle")

	Frames.Page1.Header.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page1.Header")
	Frames.Page1.Body.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page1.Body")

	Frames.Page2.Header.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page2.LogoWordmark")
	Frames.Page2.Body.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page2.FilterHdr")

	Frames.Page3.LogoWordmark.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page3.LogoWordmark")
	Frames.Page3.PageHdr.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page3.PageHdr")

	Frames.Page4.LogoWordmark.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page4.LogoWordmark")
	Frames.Page4.PageHdr.Text = Utilities.Translate("Configuraton.Admins.NewAdmin.Page4.PageHdr")

	Dots.AProgress.Text =
		string.format(Utilities.Translate("Configuration.Admins.NewAdmin.BottomData.StepLabel"), "1", "5")

	for _, Label in Frames:GetDescendants() do
		if not Label:IsA("TextLabel") then
			continue
		end
		if Label.Text ~= "Continue" then
			continue
		end

		Label.Text = Utilities.Translate("Configuration.Admins.NewAdmin.Page1.NextPage.LogoWordmark")
	end

	Frames.BottomData.Controls.ALast.MouseButton1Click:Connect(function()
		if not CanGoBack then
			return
		end
		if Page <= 1 then
			return
		end

		Page -= 1
		SwapPages(Frames[`Page{Page + 1}`], Frames[`Page{Page}`], "rbxassetid://14147040290", false, Page)
	end)

	Frames.Page1.NextPage.MouseButton1Click:Connect(function()
		SwapPages(Frames.Page1, Frames.Loading, "rbxassetid://11102397100", true, 1)

		Env = require(script.Parent.UI.AdminHelperEnv)

		print("hi")

		local Success, FilterResult = pcall(function()
			return Var.Remotes.FilterString:InvokeServer("test string")
		end)

		print(Success, FilterResult)

		if Success and FilterResult[1] then
			SwapPages(Frames.Loading, Frames.Page2, "rbxassetid://15084609272", false, 2)

			ConnectionsTable = {
				Frames.Page2.TextInput.FocusLost:Connect(function(_)
					Frames.Page2.PreviewText.Text =
						`Preview: {Var.Remotes.FilterString:InvokeServer(Frames.Page2.TextInput.Text)[2]}`
				end),

				Frames.Page2.ColorInput:GetPropertyChangedSignal("Text"):Connect(function()
					xpcall(function()
						TweenService:Create(
							Frames.Page2.ColorPreview,
							TweenInfo.new(Var.AnimationSpeed * 0.3, Enum.EasingStyle.Quart),
							{
								BackgroundColor3 = Color3.fromHex(Frames.Page2.ColorInput.Text),
							}
						):Play()
					end, function()
						TweenService:Create(
							Frames.Page2.ColorPreview,
							TweenInfo.new(Var.AnimationSpeed * 0.3, Enum.EasingStyle.Quart),
							{
								BackgroundColor3 = Color3.fromHex("#fff"),
							}
						):Play()
					end)
				end),
			}

			Frames.Page2.TextInput.Text = Env.EditModeName
			Frames.Page2.ColorInput.Text = Env.EditModeColor
		else
			Frames.Page6.Header.Text = Utilities.Translate("admin.rankcreator.failed.Detail")
			Frames.Page6.Body.Text =
				string.format(Utilities.Translate("admin.rankcreator.errors.filter.Body"), FilterResult[2])

			SwapPages(Frames.Loading, Frames.Page6, "rbxassetid://14147040290", false, 5)
		end
	end)

	Frames.Page2.NextPage.MouseButton1Click:Connect(function()
		if string.len(Frames.Page2.TextInput.Text) == 0 or string.len(Frames.Page2.TextInput.Text) > 50 then
			Frontend.Toast({
				Icon = Utilities.Icon("x"),
				Text = Utilities.Translate("generic.InvalidInput"),
				Subtext = Utilities.Translate("admin.rankcreator.errors.name.Len"),
				Timeout = 5,
			})

			return
		end

		SwapPages(Frames.Page2, Frames.Loading, "rbxassetid://11102397100", true, 2)

		local ExistingRank = Var.Remotes.GetRank:InvokeServer(Frames.Page2.TextInput.Text)
		if ExistingRank ~= nil and not Env.EditMode then
			Frontend.Toast({
				Icon = Utilities.Icon("x"),
				Text = Utilities.Translate("generic.InvalidInput"),
				Subtext = string.format(
					Utilities.Translate("admin.rankcreator.errors.name.Unique"),
					Frames.Page2.TextInput.Text
				),
				Timeout = 5,
			})

			SwapPages(Frames.Loading, Frames.Page2, "rbxassetid://11102397100", false)

			return
		end

		for _, Connection in ConnectionsTable do
			Connection:Disconnect()
		end

		for i, v in Frames.Page3.Members.Members:GetChildren() do
			if not v:GetAttribute("IsTemplate") and v:IsA("Frame") then
				v:Destroy()
			end
		end

		local Checking = false
		local Thread
		local function NewGroupCard(PresetID: number?, PresetRank: number?)
			local Clone = Frames.Page3.Members.Members.GroupTemplate:Clone()

			Clone.Parent = Frames.Page3.Members.Members
			Clone.Visible = true
			Clone:SetAttribute("IsTemplate", false)
			Clone:SetAttribute("TemplateType", "Group")

			Clone.Label.Text = Utilities.Translate("Configuration.Admins.EditRank.People.Content.GroupTemplate.Label")

			local CheckTask = function()
				Checking = true
				local Success, Info = pcall(function()
					return game:GetService("GroupService"):GetGroupInfoAsync(tonumber(Clone.TextInput.Text))
				end)

				if Success then
					Clone._Name.Text = `{Info["Name"]}`
					Clone.Image.Image = Info["EmblemUrl"]
				else
					Clone._Name.Text = Utilities.Translate("generic.NotFound")
					Clone.Image.Image = "rbxassetid://15105863258"
				end

				Checking = false
			end

			local Thread
			ConnectionsTable["Event" .. math.random(1, 500)] = Clone.TextInput
				:GetPropertyChangedSignal("Text")
				:Connect(function()
					if Checking then
						task.cancel(Thread)

						Thread = task.spawn(CheckTask)
					else
						Thread = task.spawn(CheckTask)
					end
				end)

			ConnectionsTable["Close" .. math.random(1, 500)] = Clone.Delete.MouseButton1Click:Connect(function()
				Clone:Destroy()
			end)

			Clone.TextInput.Text = PresetID or ""
			Clone.GroupRankInput.Text = PresetRank or ""
		end

		local function NewUserCard(PresetID: number?)
			local Clone = Frames.Page3.Members.Members.PlayerTemplate:Clone()

			Clone.Parent = Frames.Page3.Members.Members
			Clone.Visible = true

			Clone:SetAttribute("IsTemplate", false)
			Clone:SetAttribute("TemplateType", "User")

			Clone.Label.Text = Utilities.Translate("Configuration.Admins.EditRank.People.Content.PlayerTemplate.Label")

			local function CheckTask()
				local Success, Info = pcall(function()
					return {
						game.Players:GetNameFromUserIdAsync(tonumber(Clone.TextInput.Text)),
						game.Players:GetUserThumbnailAsync(
							tonumber(Clone.TextInput.Text),
							Enum.ThumbnailType.HeadShot,
							Enum.ThumbnailSize.Size100x100
						),
					}
				end)

				if Success then
					Clone._Name.Text = Info[1]
					Clone.Image.Image = Info[2]
				else
					Clone._Name.Text = Utilities.Translate("generic.NotFound")
					Clone.Image.Image = "rbxassetid://15105863258"
				end
			end

			ConnectionsTable["Event" .. math.random(1, 500)] = Clone.TextInput
				:GetPropertyChangedSignal("Text")
				:Connect(function()
					if Checking then
						task.cancel(Thread)

						Thread = task.spawn(CheckTask)
					else
						Thread = task.spawn(CheckTask)
					end
				end)

			ConnectionsTable["Close" .. math.random(1, 500)] = Clone.Delete.MouseButton1Click:Connect(function()
				Clone:Destroy()
			end)

			Clone.TextInput.Text = PresetID or ""
		end

		ConnectionsTable = {
			Frames.Page3.AddPane.AddGroup.Click.MouseButton1Click:Connect(NewGroupCard),
			Frames.Page3.AddPane.AddUser.Click.MouseButton1Click:Connect(NewUserCard),
		}

		Frames.Page3.AddPane.AddGroup.LogoWordmark.Text =
			Utilities.Translate("Configuration.Admins.EditRank.People.Content.GroupTemplate.Label")
		Frames.Page3.AddPane.AddUser.LogoWordmark.Text =
			Utilities.Translate("Configuration.Admins.EditRank.People.Content.PlayerTemplate.Label")

		for i, User in Env.EditModeMembers :: { { MemberType: string, ID: number, GroupRank: number? } } do
			if User.MemberType == "User" then
				NewUserCard(User.ID)
			else
				NewGroupCard(User.ID, User.GroupRank)
			end
		end

		SwapPages(Frames.Loading, Frames.Page3, "rbxassetid://15082548595", false, 3)
	end)

	Frames.Page3.NextPage.MouseButton1Click:Connect(function()
		SwapPages(Frames.Page3, Frames.Loading, "rbxassetid://11102397100", true, 3)

		local MemberCount = 0
		for i, v in Frames.Page3.Members.Members:GetChildren() do
			if not v:IsA("Frame") then
				continue
			end
			if v:GetAttribute("IsTemplate") then
				continue
			end

			MemberCount += 1
		end

		if MemberCount == 0 then
			Frontend.Toast({
				Icon = Utilities.Icon("x"),
				Text = Utilities.Translate("generic.InvalidInput"),
				Subtext = Utilities.Translate("admin.rankcreator.errors.members.NotEnough"),
				Timeout = 5,
			})

			SwapPages(Frames.Loading, Frames.Page3, "rbxassetid://15082548595", false, 3)

			return
		elseif MemberCount > Env.MaxPeople then
			Frontend.Toast({
				Icon = Utilities.Icon("x"),
				Text = Utilities.Translate("generic.InvalidInput"),
				Subtext = string.format(Utilities.Translate("admin.rankcreator.errors.members.TooMany")),
				Timeout = 5,
			})

			SwapPages(Frames.Loading, Frames.Page3, "rbxassetid://15082548595", false, 3)

			return
		end

		local ShouldGoBack = false
		local Toggled = false

		for i, v in Frames.Page3.Members.Members:GetChildren() do
			if not v:IsA("Frame") then
				continue
			end
			if v:GetAttribute("IsTemplate") then
				continue
			end

			pcall(function()
				if ShouldGoBack then
					return true
				end

				Toggled = false

				if v.TextInput.Text == "" then
					Frontend.Popup.new(
						{
							Icon = Utilities.Icon("administer"),
							Name = "Administer",
							Subheader = "Rank Creator",
						},
						{
							Primary = Utilities.Icon("warning-filled"),
							SubIcon = Utilities.Icon("x"),
						},
						Utilities.Translate("generic.InvalidInput"),
						Utilities.Translate("admin.rankcreator.errors.members.NoInput"),
						{
							{
								Text = Utilities.Translate("generic.OK"),
								Icon = Utilities.Icon("check-plain"),
								Callback = function(c)
									c()

									Toggled = true
									ShouldGoBack = true

									SwapPages(Frames.Loading, Frames.Page3, "rbxassetid://15082548595", false, 3)
								end,
							},
						}
					)
				else
					Toggled = true
				end
			end)

			repeat
				task.wait()
			until Toggled
			Toggled = false
		end

		if ShouldGoBack then
			return
		end

		ShouldGoBack = false

		for i, v in ConnectionsTable do
			v:Disconnect()
		end

		for i, Child in Frames.Page4.Apps.Apps:GetChildren() do
			if Child.Name ~= "Template" and Child:IsA("Frame") then
				Child:Destroy()
			end
		end

		local CanNotEdit = {}

		for _, AppObj in Var.CombinedButtonConfig do
			if Var.RankCreatorApps == nil then
				Var.RankCreatorApps = {
					CachedData = {},
				}
			end

			Var.RankCreatorApps[AppObj.ButtonID] = true
			Var.RankCreatorApps.CachedData[AppObj.ButtonID] = {
				Name = AppObj.AppName,
				Icon = AppObj.Icon,
			}

			for _, SubIcon in AppObj.SubIcons do
				Var.RankCreatorApps[`{AppObj.ButtonID}\\{SubIcon.ButtonID}`] = true
				Var.RankCreatorApps.CachedData[`{AppObj.ButtonID}\\{SubIcon.ButtonID}`] = {
					Name = SubIcon.Name,
					Icon = SubIcon.Icon,
				}
			end
		end

		if Env.EditModeApps ~= {} then
			for AppID, CanUse in Env.EditModeApps do
				if AppID == "CachedData" then
					continue
				end

				if not Var.RankCreatorApps[AppID] then
					table.insert(CanNotEdit, AppID)
				end

				Var.RankCreatorApps[AppID] = CanUse

			end
		end

		for i, v: Instance in Var.MainFrame.AppDrawer.AppHolder.Apps:GetChildren() do
			if Env.HasPopulatedApps then
				break
			end

			if
				not table.find({ "MultiThread", "SingleThread", "ZZ_AdministerData", "UIListLayout", "Home" }, v.Name)
			then
				if v:GetAttribute("ThreadType") == "multi" then
					local NewApp = v:Clone()

					NewApp.Parent = Frames.Page4.AppDrawer.AppHolder.Apps
					NewApp.Size = UDim2.new(0.911, 0, 0.636, 0)

					for _, App in NewApp.SubCollection:GetChildren() do
						if not App:IsA("Frame") then
							continue
						end

						for _, AppObj in Var.CombinedButtonConfig do
							for _, SubIcon in AppObj.SubIcons do
								local ButtonID = `{AppObj.ButtonID}\\{SubIcon.ButtonID}`

								if
									App:GetAttribute("ButtonID") == ButtonID
									and Var.RankCreatorApps[ButtonID] == false
								then
									TweenService:Create(App.Title, TweenInfo.new(0.4), {
										TextTransparency = Var.RankCreatorApps[ButtonID] and 0 or 0.6,
									}):Play()

									TweenService:Create(App.Icon, TweenInfo.new(0.4), {
										ImageTransparency = Var.RankCreatorApps[ButtonID] and 0 or 0.6,
									}):Play()
								end
							end
						end

						App:FindFirstChildWhichIsA("TextButton").MouseButton1Click:Connect(function()
							for _, AppObj in Var.CombinedButtonConfig do
								for _, SubIcon in AppObj.SubIcons do
									local ButtonID = `{AppObj.ButtonID}\\{SubIcon.ButtonID}`

									if App:GetAttribute("ButtonID") == ButtonID then
										Var.RankCreatorApps[ButtonID] = not Var.RankCreatorApps[ButtonID]

										TweenService
											:Create(App.Title, TweenInfo.new(0.4), {
												TextTransparency = Var.RankCreatorApps[ButtonID] and 0 or 0.6,
											})
											:Play()

										TweenService
											:Create(App.Icon, TweenInfo.new(0.4), {
												ImageTransparency = Var.RankCreatorApps[ButtonID] and 0 or 0.6,
											})
											:Play()
									end
								end
							end
						end)
					end
				else
					local NewApp = v:Clone()
					local ButtonID = NewApp:GetAttribute("ButtonID")

					NewApp.Parent = Frames.Page4.AppDrawer.AppHolder.Apps
					NewApp.Size = UDim2.new(0.911, 0, 0.13, 0)

					for _, AppObj in Var.CombinedButtonConfig do
						if AppObj.ButtonID == ButtonID and Var.RankCreatorApps[ButtonID] == false then
							TweenService:Create(NewApp.Title, TweenInfo.new(0.4), {
								TextTransparency = Var.RankCreatorApps[AppObj.ButtonID] and 0 or 0.6,
							}):Play()

							TweenService:Create(NewApp.Icon, TweenInfo.new(0.4), {
								ImageTransparency = Var.RankCreatorApps[AppObj.ButtonID] and 0 or 0.6,
							}):Play()
						end
					end

					NewApp.Activator.MouseButton1Click:Connect(function()
						for _, AppObj in Var.CombinedButtonConfig do
							if AppObj.ButtonID == ButtonID then
								Var.RankCreatorApps[AppObj.ButtonID] = not Var.RankCreatorApps[AppObj.ButtonID]

								TweenService:Create(NewApp.Title, TweenInfo.new(0.4), {
									TextTransparency = Var.RankCreatorApps[AppObj.ButtonID] and 0 or 0.6,
								}):Play()

								TweenService:Create(NewApp.Icon, TweenInfo.new(0.4), {
									ImageTransparency = Var.RankCreatorApps[AppObj.ButtonID] and 0 or 0.6,
								}):Play()
							end
						end
					end)
				end
			end
		end

		SwapPages(Frames.Loading, Frames.Page4, "rbxassetid://14865439768", false, 4)

		Env.HasPopulatedApps = true
	end)

	Frames.Page4.NextPage.MouseButton1Click:Connect(function()
		SwapPages(Frames.Page4, Frames.Loading, "", true, 4)

		if Frames.Page5:FindFirstChildWhichIsA("Frame") then
			Frames.Page5:FindFirstChildWhichIsA("Frame"):Destroy()
		end

		local Members, AllowedPages = {}, {}

		for i, v in Frames.Page3.Members.Members:GetChildren() do
			if not v:IsA("Frame") then
				continue
			end
			if v:GetAttribute("IsTemplate") then
				continue
			end

			if v:GetAttribute("TemplateType") == "Group" then
				table.insert(Members, {
					MemberType = "Group",
					ID = v.TextInput.Text or 0,
					GroupRank = v.GroupRankInput.Text or 0,
				})
			else
				table.insert(Members, {
					MemberType = "User",
					ID = v.TextInput.Text or 0,
				})
			end
		end

		if Var.RankCreatorApps.SuperAdmin == nil then
			Var.RankCreatorApps.SuperAdmin = false
		end

		NewCard({
			Name = Var.Remotes.FilterString:InvokeServer(Frames.Page2.TextInput.Text)[2],
			Protected = false,
			Members = Members,

			Apps = Var.RankCreatorApps,

			CreatorID = game.Players.LocalPlayer.UserId,
			Color = Frames.Page2.ColorInput.Text,
			CreationReason = "Created in the Rank Creator",
			Modified = os.time(),
			RankID = -1,
		}, Frames.Page5, true).Position =
			UDim2.fromScale(0.156, 0.319)

		SwapPages(Frames.Loading, Frames.Page5, Utilities.Icon("check-plain"), false, 5)
	end)

	Frames.Page5.NextPage.MouseButton1Click:Connect(function()
		CanGoBack = false

		SwapPages(Frames.Page5, Frames.Loading, "", true, 5)

		local Members, AllowedPages = {}, {}

		for i, v in Frames.Page3.Members.Members:GetChildren() do
			if not v:IsA("Frame") then
				continue
			end
			if v:GetAttribute("IsTemplate") then
				continue
			end

			if v:GetAttribute("TemplateType") == "Group" then
				table.insert(Members, {
					MemberType = "Group",
					ID = v.TextInput.Text or 0,
					GroupRank = v.GroupRankInput.Text or 0,
				})
			else
				table.insert(Members, {
					MemberType = "User",
					ID = v.TextInput.Text or 0,
				})
			end
		end

		FinalData = {
			Name = Var.Remotes.FilterString:InvokeServer(Frames.Page2.TextInput.Text)[2],
			Protected = false,
			Members = Members,

			Apps = Var.RankCreatorApps,

			ActingUser = game.Players.LocalPlayer.UserId,
			Color = Frames.Page2.ColorInput.Text,

			IsEditing = Env.EditMode,
			EditOriginalName = Env.EditModeName,

			CreationReason = "Created in the Rank Creator",
		}

		local Result = Var.Remotes.NewRank:InvokeServer(FinalData)
		if Result[1] then
			SwapPages(Frames.Loading, Frames.Page6, "rbxassetid://13531414092", false, 6)
			Frames.Page6.Header.Text = Env.Strings.FinHeaderSucc
			Frames.Page6.Body.Text = Env.Strings.FinBodyNew
		else
			SwapPages(Frames.Loading, Frames.Page6, "rbxassetid://13531414092", false, 6)
			Frames.Page6.Header.Text = Env.Strings.FinHeaderError
			Frames.Page6.Body.Text = string.format(Env.Strings.FinBodyNewError, Result[2])
		end
	end)

	Frames.Page6.NextPage.MouseButton1Click:Connect(function()
		Admins.Load()
		Admins.CloseCreator()
		Admins.ClearEditState(Env)

		SwapPages(Frames.Page6, Frames.Page1, "rbxassetid://18151072839", false, 1)

		Frames.BottomData.RankTitle.Text = Utilities.Translate("Configuration.Admins.NewAdmin.BottomData.RankTitle")
		CanGoBack = true
	end)

	Frames.BottomData.Controls.Exit.MouseButton1Click:Connect(function()
		Admins.CloseCreator()
	end)
end

return Admins


-- AjaxTiba

-- Services
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local guiService = game:GetService("GuiService")

local Frontend = require(script.Parent.Parent.Parent.Frontend)
local Utilities = require(script.Parent.Parent.Parent.Utilities)

local module = {}

module.__index = module

function module.createDropdown(
	bounds: GuiButton,
	indicationText: TextLabel,
	list: GuiObject,
	template: GuiObject,
	parent: Instance,
	items: {},
	SettingName
)
	local self = {}

	self.boundingArea = bounds
	self.indicatorText = indicationText

	self.value = items[1]

	self.openMenu = nil

	self.MenuOpened = Instance.new("BindableEvent")
	self.Opened = self.MenuOpened.Event
	self.MenuClosed = Instance.new("BindableEvent")
	self.Closed = self.MenuClosed.Event
	self.ValueChangedBindable = Instance.new("BindableEvent")
	self.ValueChanged = self.ValueChangedBindable.Event

	self.boundingArea.MouseButton1Down:Connect(function()
		if self.openMenu then
			self.openMenu:Destroy()
			self.openMenu = nil
			self.MenuClosed:Fire()
			return
		end

		local inset = game:GetService("GuiService"):GetGuiInset()
		local dropdownMenu = list:Clone()
		local LanguageNames

		dropdownMenu.Visible = true
		dropdownMenu.Parent = parent
		dropdownMenu.Size = UDim2.new(0, bounds.AbsoluteSize.X, 0, bounds.AbsoluteSize.Y * 3)
		dropdownMenu.Position =
			UDim2.new(0, bounds.AbsolutePosition.X, 0, bounds.AbsolutePosition.Y + bounds.AbsoluteSize.Y + inset.Y)

		self.openMenu = dropdownMenu
		self.MenuOpened:Fire()

		if SettingName and string.find(SettingName, "Language") ~= nil then
			LanguageNames = game.ReplicatedStorage.Administer.GetLocaleNames:InvokeServer()
		end

		for i, v in items do
			local item = template:Clone()
			item.Parent = dropdownMenu:FindFirstChildWhichIsA("ScrollingFrame")
			item.Visible = true

			local button = item:FindFirstChildWhichIsA("GuiButton")
			local label = item:FindFirstChildWhichIsA("TextLabel")

			if LanguageNames then
				label.Text = `{LanguageNames[v]} [{v}]`
			else
				label.Text = v
			end

			button.MouseButton1Click:Connect(function()
				self:SetValue(v)

				if LanguageNames then
					Frontend.Popup.new(
						{
							Icon = Utilities.Icon("administer"),
							Name = "Administer",
						},
						{
							Primary = Utilities.Icon("translate"),
							SubIcon = Utilities.Icon("administer"),
						},
						game.ReplicatedStorage.Administer.DirectTranslate:InvokeServer(
							v,
							"setting.Locale.Swapped.Title"
						),
						game.ReplicatedStorage.Administer.DirectTranslate:InvokeServer(v, "setting.Locale.Swapped.Body"),
						{
							{
								Text = game.ReplicatedStorage.Administer.DirectTranslate:InvokeServer(v, "generic.OK"),
								Icon = Utilities.Icon("check-plain"),
								Callback = function(a)
									a()
								end,
							},
						}
					)
				end

				self.openMenu = false

				dropdownMenu:Destroy()
				self.MenuClosed:Fire()
			end)
		end
	end)

	self = setmetatable(self, module)

	return self
end

function module:SetValue(value)
	self.indicatorText.Text = value

	if value ~= self.value then
		self.value = value

		self.ValueChangedBindable:Fire(self.value)
	end
end

return module


-- AjaxTiba

-- Services
local runService = game:GetService("RunService")
local guiService = game:GetService("GuiService")

local module = {}

module.__index = module
local LastGoodWidth

function module.setupTextBox(textBox: TextBox)
	local self = {}

	self.textBox = textBox
	self.value = ""

	self.ValueChangedBindable = Instance.new("BindableEvent")
	self.ValueChanged = self.ValueChangedBindable.Event

	if runService:IsClient() then
		self.textBox.FocusLost:Connect(function(enterPressed)
			if not enterPressed then
				return
			end
			self:SetValue(self.textBox.Text)
		end)

		self.textBox:GetPropertyChangedSignal("Text"):Connect(function()

		end)
	end

	self = setmetatable(self, module)

	return self
end

function module:SetValue(value)
	if value ~= self.value then
		self.value = value

		self.textBox.Text = value

		self.ValueChangedBindable:Fire(self.value)
	end
end

return module


-- AjaxTiba

-- Services
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local guiService = game:GetService("GuiService")

local module = {}

module.__index = module

function module.createKeybindListener(bounds: GuiButton, indicationText: TextLabel)
	local self = {}

	self.boundingArea = bounds
	self.indicationText = indicationText

	self.value = Enum.KeyCode
	self.nameValue = ""

	self.listening = false

	self.listeningBindable = Instance.new("BindableEvent")
	self.listeningStarted = self.listeningBindable.Event
	self.ValueChangedBindable = Instance.new("BindableEvent")
	self.ValueChanged = self.ValueChangedBindable.Event

	self.boundingArea.MouseButton1Click:Connect(function()
		local pressedKeys = {}
		self.listening = true
		self.boundingArea.Interactable = false
		self.listeningBindable:Fire()
		indicationText.Text = "..."
		local connection0
		local connection1
		connection0 = userInputService.InputBegan:Connect(function(input)
			table.insert(pressedKeys, input.KeyCode)
		end)

		connection1 = userInputService.InputEnded:Connect(function(input)
			if input.KeyCode == pressedKeys[1] then
				self:SetValue(pressedKeys)
				self.listening = false
				self.boundingArea.Interactable = true

				connection0:Disconnect()
				connection1:Disconnect()
			end
		end)
	end)

	self = setmetatable(self, module)

	return self
end

function module:SetValue(value: { Enum.KeyCode })
	if value ~= self.value then
		self.value = value
		local commaSeparated = {}
		for i, v in pairs(value) do
			table.insert(commaSeparated, v.Name)
		end
		commaSeparated = table.concat(commaSeparated, ",")
		self.commaSeparatedValue = commaSeparated

		self.indicationText.Text = commaSeparated

		self.ValueChangedBindable:Fire(self.value.Name)
	end
end

return module


-- AjaxTiba

-- Services
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local guiService = game:GetService("GuiService")

local module = {}

module.__index = module

function module.createSlider(bounds: GuiButton, min, max, step, fill: Frame, head: Frame)
	local self = {}

	self.boundingArea = bounds
	self.fill = fill
	self.head = head

	self.minimumValue = min
	self.maximumValue = max
	self.roundingValue = step
	self.value = 0

	self.dragging = false

	self.dragStartBindable = Instance.new("BindableEvent")
	self.DragBegin = self.dragStartBindable.Event
	self.dragEndBindable = Instance.new("BindableEvent")
	self.DragEnded = self.dragEndBindable.Event
	self.ValueChangedBindable = Instance.new("BindableEvent")
	self.ValueChanged = self.ValueChangedBindable.Event

	self.boundingArea.MouseButton1Down:Connect(function()
		self.dragging = true
		self.dragStartBindable:Fire()

		repeat
			local mousePos = userInputService:GetMouseLocation().X
			local barPos = self.boundingArea.AbsolutePosition.X
			local xPos = mousePos - barPos
			local range = (self.maximumValue - self.minimumValue)
			local barSize = self.boundingArea.AbsoluteSize.X
			local rawValue = math.clamp(xPos / barSize, 0, 1) * range + self.minimumValue

			local roundValue = math.round(rawValue / self.roundingValue) * self.roundingValue

			self:SetValue(roundValue)

			runService.RenderStepped:Wait()
		until not self.dragging
	end)

	userInputService.InputEnded:Connect(function(inputObject, processed)
		if self.dragging then
			if
				inputObject.UserInputType == Enum.UserInputType.MouseButton1
				or inputObject.UserInputType == Enum.UserInputType.Touch
			then
				self.dragging = false

				self.dragEndBindable:Fire()
			end
		end
	end)

	self = setmetatable(self, module)

	return self
end

function module:SetValue(value)
	if value ~= self.value then
		self.value = value

		local range = (self.maximumValue - self.minimumValue)
		local x = (self.value - self.maximumValue) / range + 1

		if self.fill then
			self.fill.Size = UDim2.new(x, 0, 1, 0)
		end

		if self.head then
			self.head.Position = UDim2.new(x, 0, 0.5, 0)
		end

		self.ValueChangedBindable:Fire(self.value)
	end
end

return module


-- AjaxTiba

-- Services
local tweenService = game:GetService("TweenService")

local module = {}

module.__index = module

function module.createSwitch(bounds: GuiButton, indicator: TextLabel)
	local self = {}

	self.boundingArea = bounds
	self.indicatingText = indicator
	self.value = false

	bounds.MouseButton1Click:Connect(function()
		self:SetValue(not self.value)
	end)

	self.valueChangedBindable = Instance.new("BindableEvent")
	self.ValueChanged = self.valueChangedBindable.Event

	self = setmetatable(self, module)

	return self
end

function module:SetValue(value)
	if value ~= self.value then
		self.value = value
		if value == true then
			self.indicatingText.Text = "Enabled"
		else
			self.indicatingText.Text = "Disabled"
		end

		local properties = {}

		self.valueChangedBindable:Fire(self.value)
	end
end

return module


--// Administer
--// CodingAgent 2024-2026

local Frontend = { Popup = {}, Drawer = {} }

local Libraries = script.Parent.Parent.Libraries
local Modules = script.Parent

local Utilities = require(Modules.Utilities)
local Ripple = require(Modules.Parent.Parent.ButtonAnims)
local Var = require(Modules.Variables)
local Types = require(Modules.Types)

function Frontend.Render() end

function Frontend.CloneElement(Element: GuiObject, Props: {}, OnClone: ((Clone: GuiObject) -> ())?): ()
	local Clone = Element:Clone()

	for Property, Value in Props do
		Clone[Property] = Value
	end

	Clone.Parent = Element.Parent

	if typeof(OnClone) == "nil" then
		return Clone
	else
		return OnClone(Clone)
	end
end

function Frontend.Log(Text, LogLevel)
	return { MainFrame = {} }
end

function Frontend.ToggleFullscreen(ForceClose: boolean, TargetFrame: Frame | CanvasGroup): ()
	if not TargetFrame then
		Utilities.Logging.Error("A TargetFrame is required to resize")
	end

	local Speed = Var.AnimationSpeed * 0.75
	local Header = Var.MainFrame:FindFirstChild("Header")

	if TargetFrame:GetAttribute("IsFullScreen") == true or ForceClose == true then
		TargetFrame:SetAttribute("IsFullScreen", false)

		Var.Services.TweenService
			:Create(
				Var.MainFrame,
				TweenInfo.new(Speed, Enum.EasingStyle.Quart),
				{ Size = UDim2.fromScale(0.843, 0.708) }
			)
			:Play()
		Var.Services.TweenService
			:Create(
				Var.MainFrame.UICorner,
				TweenInfo.new(Speed, Enum.EasingStyle.Quart),
				{ CornerRadius = UDim.new(0, 20) }
			)
			:Play()
		if Header then
			Var.Services.TweenService
				:Create(
					Header.Mark,
					TweenInfo.new(Speed, Enum.EasingStyle.Quart),
					{ Position = UDim2.new(0.328, 0, 0, 0) }
				)
				:Play()
		end
	else
		TargetFrame:SetAttribute("IsFullScreen", true)

		Var.Services.TweenService
			:Create(
				Var.MainFrame,
				TweenInfo.new(Speed, Enum.EasingStyle.Quart),
				{ Size = UDim2.fromScale(1, 1), Position = UDim2.fromScale(0.5, 0.5) }
			)
			:Play()
		Var.Services.TweenService
			:Create(
				Var.MainFrame.UICorner,
				TweenInfo.new(Speed, Enum.EasingStyle.Quart),
				{ CornerRadius = UDim.new(0, 0) }
			)
			:Play()
		if Header then
			Var.Services.TweenService
				:Create(Header.Mark, TweenInfo.new(Speed, Enum.EasingStyle.Quart), {
					Position = UDim2.new(0.328, Var.Services.GUIService.TopbarInset.Min.X, 0, 0),
					Size = UDim2.new(Header.Mark.Size.X.Scale, 0, 0, Var.Services.GUIService.TopbarInset.Height),
				})
				:Play()
		end
	end
end

function Frontend.Open(WaitForCompletion: boolean): ()
	local AS = Var.AnimationSpeed
	local X = 0.85
	local Y = 0.7
	Var.MainFrame.GroupTransparency = 1

	Var.IsPanelAnimating = true
	Var.MainFrame.Visible = true
	if Var.UseAcrylic then
		require(Libraries.Neon):BindFrame(Var.MainFrame, {
			Transparency = 0.95,
			BrickColor = BrickColor.new("Institutional white"),
		})
	end

	local PopupTween

	if not Var.Mobile then
		script.Parent.Parent.Assets.PanelOpen:Play()

		AS *= 0.55

		Var.MainFrame.Position = UDim2.fromScale(0.5, 0.5)
		Var.MainFrame.Size = UDim2.fromScale(Var.MainFrame.Size.X.Scale * 0.9, Var.MainFrame.Size.Y.Scale * 0.9)

		PopupTween = Var.Services.TweenService:Create(Var.MainFrame, TweenInfo.new(AS, Enum.EasingStyle.Cubic), {
			Size = UDim2.fromScale(Var.MainFrame.Size.X.Scale * 1.1, Var.MainFrame.Size.Y.Scale * 1.1),
			GroupTransparency = 0,
		})
	else
		Var.MainFrame.Position = UDim2.fromScale(1.5, 0.5)

		Var.Services.TweenService
			:Create(
				Var.MainFrame,
				TweenInfo.new(AS, Enum.EasingStyle.Quart, Enum.EasingDirection.Out, 0, false, AS * 0.2),
				{
					Size = UDim2.fromScale(X, Y),
				}
			)
			:Play()

		PopupTween = Var.Services.TweenService:Create(
			Var.MainFrame,
			TweenInfo.new(AS, Enum.EasingStyle.Cubic),
			{ Position = UDim2.fromScale(0.5, 0.5), GroupTransparency = 0 }
		)
	end

	PopupTween:Play()
	task.delay(AS, function()
		Var.IsPanelAnimating = false
		Var.IsOpen = true
	end)

	if WaitForCompletion then
		task.wait(AS)
	end
end

function Frontend.Close(Instant: boolean? | CanvasGroup? | Frame?, WaitForCompletion, Frame: CanvasGroup? | Frame?): ()
	if typeof(Instant) ~= "boolean" then
		Frame = Instant
		Instant = false
	end

	if not Frame then
		Frame = Var.MainFrame
	end

	Var.IsPanelAnimating = true

	xpcall(function(...)
		require(Libraries.Neon):UnbindFrame(Var.MainFrame)
	end, function(a0)
		Var.InitErrored = true
	end)

	local Duration = 0
	if not Instant then
		Duration = Var.AnimationSpeed
	end

	if not Var.Mobile then
		Duration *= 0.55

		Var.Services.TweenService
			:Create(Var.MainFrame, TweenInfo.new(Duration, Enum.EasingStyle.Cubic), {
				Size = UDim2.fromScale(Var.MainFrame.Size.X.Scale * 0.9, Var.MainFrame.Size.Y.Scale * 0.9),
				GroupTransparency = 1,
			})
			:Play()
	else
		Var.Services.TweenService
			:Create(Frame, TweenInfo.new(Duration, Enum.EasingStyle.Quart, Enum.EasingDirection.Out), {
				Size = UDim2.fromScale(Var.MainFrame.Size.X.Scale / 1.5, Var.MainFrame.Size.Y.Scale / 1.5),
				Position = UDim2.fromScale(1.5, 0.5),
				GroupTransparency = 1,
			})
			:Play()
	end

	task.delay(Duration, function()
		Frame.Visible = false

		if Frame == Var.MainFrame then
			Var.IsPanelAnimating = false
			Var.MainFrame.Visible = false
			Var.IsOpen = false
		end
	end)

	task.defer(function()
		Frontend.ToggleFullscreen(true, Var.MainFrame)
	end)

	if WaitForCompletion then
		task.wait(Duration)
	end
end

local DrawerConnections = {}
local ShouldAnimate = true
local IsQueued = false
local CurrentlyActive
local Ready = true
local Card

function Frontend.Drawer.Open(): ()
	if not Var.DoHeaderEffects then
		return
	end
	if Var.PopupOpen then
		return
	end

	Frontend.Drawer.HoverEnd()

	local Apps = Var.MainFrame.AppDrawer
	local Container = Instance.new("CanvasGroup")
	local UiC = Instance.new("UICorner")
	local TimeToComplete

	Var.DoHeaderEffects = false
	ShouldAnimate = true
	Ready = true

	TimeToComplete = Var.AnimationSpeed * 2

	Container.Size = UDim2.new(1, 0, 1, 0)
	Container.Position = UDim2.new(0, 0, 0, 0)

	Container.ZIndex = 99999
	Container.Parent = Apps.AppDrawerCover
	Container.BackgroundTransparency = 1
	Container.BackgroundColor3 = Color3.fromRGB(11, 12, 17)

	UiC.CornerRadius = UDim.new(0, 18)
	UiC.Parent = Container

	Apps.Visible = true
	Apps.Position = UDim2.new(0, 0, 0.75, 0)

	Apps.AppHolder.Position = UDim2.new(0, 0, 0.45, 0)

	local function AppOver(AppConfig, ButtonConfig, AppVisible)
		local ShouldBind

		xpcall(function()
			Card = Apps.AppDrawerCover.Card
			ShouldBind = true
		end, function()
			Card = Var.MainFrame.Parent.Card
			ShouldBind = AppVisible
		end)

		if AppVisible then
			Card.AppPrimary.Image = AppConfig.Icon
			Card.AppMenu.Image = ButtonConfig.Icon

			Card.Title.Text = AppConfig.AppName
			Card.SubTitle.Text = ButtonConfig.Name
			Card.Desc.Text = AppConfig.Description

			Card.Parent = Var.MainFrame.Parent

			game:GetService("TweenService")
				:Create(Card, TweenInfo.new(Var.AnimationSpeed * 0.15), { GroupTransparency = 0 })
				:Play()

			if ShouldBind then
				DrawerConnections[`CardMovement`] = game:GetService("RunService").RenderStepped:Connect(function(dt)
					if Card.Visible == false then
						return
					end

					local Mouse = game:GetService("UserInputService"):GetMouseLocation()
					local Pos = Vector2.new(Mouse.X, Mouse.Y - game:GetService("GuiService"):GetGuiInset().Y)

					game:GetService("TweenService")
						:Create(Card, TweenInfo.new(Var.AnimationSpeed * 0.25), {
							Position = UDim2.fromOffset(Pos.X, Pos.Y),
						})
						:Play()
				end)
			end
		else
			game:GetService("TweenService")
				:Create(Card, TweenInfo.new(Var.AnimationSpeed * 0.15), { GroupTransparency = 1 })
				:Play()

			DrawerConnections["CardMovement"]:Disconnect()
		end
	end

	for _, Child in Var.MainFrame:GetChildren() do
		if
			(Child:IsA("Frame") or Child:IsA("CanvasGroup")) and Child.Name == Var.ActivePage.Name
			or Child.Name == "Header"
			or Child:FindFirstChild(Var.ActivePage.Name)
		then
			Child.Parent = Container

			if Child.Name == Var.ActivePage.Name then
				CurrentlyActive = Child
			end
		end
	end

	Var.Services.TweenService
		:Create(Container, TweenInfo.new(TimeToComplete, Enum.EasingStyle.Quart, Enum.EasingDirection.Out, 0, false), {
			GroupTransparency = 0,
			BackgroundTransparency = 0.25,
			Size = UDim2.new(0.95, 0, 0.95, 0),
			Position = UDim2.new(0.5, 0, 0.5, 0),
			AnchorPoint = Vector2.new(0.5, 0.5),
		})
		:Play()

	Var.Services.TweenService
		:Create(Apps, TweenInfo.new(TimeToComplete * 0.3, Enum.EasingStyle.Quart), {
			Position = UDim2.new(0, 0, 0, 0),
		})
		:Play()

	Var.Services.TweenService
		:Create(Apps.AppHolder, TweenInfo.new(TimeToComplete * 0.55, Enum.EasingStyle.Quart), {
			GroupTransparency = 0,
			Position = UDim2.new(0, 0, 0, 0),
		})
		:Play()

	for _, Button in Apps.AppHolder:GetDescendants() do
		if
			Button.Name ~= "Activator"
			or Button:FindFirstAncestor("MultiThread")
			or Button:FindFirstAncestor("SingleThread")
		then
			continue
		end

		DrawerConnections[`Over-{math.random(1, 10000)}`] = Button.MouseEnter:Connect(function()
			for _, Object in Var.CombinedButtonConfig do
				for _, SubIcon in Object.SubIcons do
					if SubIcon.Icon ~= Button.Parent.Icon.Image then
						continue
					end

					task.defer(function()
						AppOver(Object, SubIcon, true)
					end)
				end
			end
		end)

		DrawerConnections[`Over-{math.random(1, 10000)}`] = Button.MouseLeave:Connect(function()
			for _, Object in Var.CombinedButtonConfig do
				for _, SubIcon in Object.SubIcons do
					if SubIcon.Icon ~= Button.Parent.Icon.Image then
						continue
					end

					task.defer(function()
						AppOver(Object, SubIcon, false)
					end)
				end
			end
		end)
	end
end

function Frontend.Drawer.Close(): ()
	local Apps = Var.MainFrame.AppDrawer
	local Container = Apps.AppDrawerCover.CanvasGroup
	local TimeToComplete = Var.AnimationSpeed

	ShouldAnimate = false

	Container.Parent.Parent = Var.MainFrame
	Container.Parent.Size = UDim2.new(0.75, 0, 1, 0)
	Container.Parent.Position = UDim2.new(0.25, 0, 0, 0)

	Var.Services.TweenService
		:Create(Apps, TweenInfo.new(TimeToComplete * 0.75, Enum.EasingStyle.Quart), {
			Position = UDim2.new(0, 0, 1, 0),
		})
		:Play()

	Var.Services.TweenService
		:Create(Apps.AppHolder, TweenInfo.new(TimeToComplete * 0.55, Enum.EasingStyle.Quart), {
			Position = UDim2.new(0, 0, 0.75, 0),
			GroupTransparency = 1,
		})
		:Play()

	Var.Services.TweenService
		:Create(
			Container.Parent,
			TweenInfo.new(TimeToComplete * 0, Enum.EasingStyle.Quart, Enum.EasingDirection.Out, 0, false),
			{
				Position = UDim2.new(0.5, 0, 0.5, 0),
				Size = UDim2.new(1, 0, 1, 0),

				AnchorPoint = Vector2.new(0.5, 0.5),
				BackgroundTransparency = 1,
			}
		)
		:Play()

	pcall(function()
		Var.Services.TweenService:Create(Card, TweenInfo.new(TimeToComplete * 0.15), { GroupTransparency = 1 }):Play()

		DrawerConnections["CardMovement"]:Disconnect()
	end)

	Var.Services.TweenService
		:Create(Container, TweenInfo.new(TimeToComplete * 0.5, Enum.EasingStyle.Quart), {
			Size = UDim2.new(1, 0, 1, 0),

			BackgroundTransparency = 1,
			GroupTransparency = 0,
		})
		:Play()

	task.wait(TimeToComplete * 0.5)

	for _, Child in Container:GetChildren() do
		if Child:IsA("Frame") or Child:IsA("CanvasGroup") then
			Child.Parent = Var.MainFrame
		end
	end

	Container.Parent.Parent = Apps
	Container.Parent.Size = UDim2.new(3, 0, 1, 0)
	Container.Parent.Position = UDim2.new(1, 0, 0, 0)
	Container.Parent.AnchorPoint = Vector2.new(0, 0)

	Container:Destroy()

	for _, Connection in DrawerConnections do
		Connection:Disconnect()
	end

	Var.DoHeaderEffects = true
	Ready = true
end

function Frontend.Drawer.HoverBegin()
	if not Var.DoHeaderEffects then
		return
	end

	local MarkBox = Var.MainFrame.Header.Mark.AppLogo
	local QuickTI = TweenInfo.new(Var.AnimationSpeed * 0.25, Enum.EasingStyle.Quart)

	Var.Services.TweenService
		:Create(MarkBox.GridIcon, QuickTI, {
			Size = UDim2.new(0.75, 0, 0.75, 0),
		})
		:Play()

	Var.Services.TweenService
		:Create(MarkBox.AppIcon, QuickTI, {
			Size = UDim2.new(0.25, 0, 0.25, 0),
			ImageTransparency = 0.75,
		})
		:Play()
end

function Frontend.Drawer.HoverEnd()
	if not Var.DoHeaderEffects then
		return
	end

	local MarkBox = Var.MainFrame.Header.Mark.AppLogo
	local QuickTI = TweenInfo.new(Var.AnimationSpeed * 0.25, Enum.EasingStyle.Quart)

	Var.Services.TweenService
		:Create(MarkBox.GridIcon, QuickTI, {
			Size = UDim2.new(0, 0, 0, 0),
		})
		:Play()

	Var.Services.TweenService
		:Create(MarkBox.AppIcon, QuickTI, {
			Size = UDim2.new(1, 0, 1, 0),
			ImageTransparency = 0,
		})
		:Play()
end

function Frontend.Toast(Config: {
	Text: string,
	Subtext: string,
	Icon: string,
	Timeout: number,

	OnClick: () -> ()?,
})
	local Toast = Var.MainFrame.administer.Toast
	local Close = nil

	Toast.Size = UDim2.fromScale(0.4, 0.74)
	Toast.Position = UDim2.fromScale(0.5, 1.1)
	Toast.Timer.Size = UDim2.fromScale(1, 1)

	Toast.HeaderLabel.Text = Config.Text
	Toast.MainText.Text = Config.Subtext
	Toast.Icon.Image = Config.Icon

	Toast.Visible = true

	Var.Services.TweenService
		:Create(Toast, TweenInfo.new(Var.AnimationSpeed * 0.6, Enum.EasingStyle.Quart), {
			Position = UDim2.fromScale(0.5, 0.879),
			Size = UDim2.fromScale(0.443, 0.094),
		})
		:Play()

	local Timer = Var.Services.TweenService:Create(Toast.Timer, TweenInfo.new(Config.Timeout), {
		Size = UDim2.fromScale(0, 1),
	})

	Timer:Play()
	script.Parent.Parent.Assets.ToastSound:Play()

	local ClickEvent = Toast.Click.MouseButton1Click:Connect(function()
		Close()

		if Config.OnClick then
			xpcall(Config.OnClick, Utilities.Logging.Print)
		end
	end)

	Close = function()
		local C =
			Var.Services.TweenService:Create(Toast, TweenInfo.new(Var.AnimationSpeed * 0.6, Enum.EasingStyle.Quart), {
				Position = UDim2.fromScale(0.5, 1.1),
				Size = UDim2.fromScale(0.4, 0.74),
			})

		C:Play()
		ClickEvent:Disconnect()

		C.Completed:Wait()
		Toast.Visible = false
	end

	Timer.Completed:Connect(Close)

	return Close
end

function Frontend.Popup.Open(): ()
	local BGTweenInfo = TweenInfo.new(Var.AnimationSpeed * 0.65, Enum.EasingStyle.Cubic)

	Frontend.Popup.OriginalStates = {}

	local descendant = Var.ActivePage
	local original = {
		Size = descendant.Size,
		Position = descendant.Position,
		Color = descendant.BackgroundColor3,
		AnchorPoint = descendant.AnchorPoint,
	}
	Frontend.Popup.OriginalStates[descendant] = original

	local Popup = Var.MainFrame.administer.MessageBox

	if not MessageBoxCanonicalSize then
		MessageBoxCanonicalSize = Popup.Size
	end

	local PopupOriginalSize = MessageBoxCanonicalSize
	local cs = MessageBoxCanonicalSize
	Popup.Size =
		UDim2.new(cs.X.Scale / 1.5, math.floor(cs.X.Offset / 1.5), cs.Y.Scale / 1.5, math.floor(cs.Y.Offset / 1.5))
	Popup.Position = UDim2.fromScale(0.5, 1.25)
	Popup.GroupTransparency = 0.5
	Popup.Visible = true

	local PopupTween =
		Var.Services.TweenService:Create(Popup, TweenInfo.new(Var.AnimationSpeed, Enum.EasingStyle.Cubic), {
			Position = UDim2.fromScale(0.5, 0.5),
			GroupTransparency = 0,
		})

	PopupTween:Play()
	Utilities.Logging.Print("Popup animation complete")

	Var.Services.TweenService
		:Create(Popup, TweenInfo.new(Var.AnimationSpeed * 0.85, Enum.EasingStyle.Cubic), {
			Size = PopupOriginalSize,
		})
		:Play()

	Var.PopupOpen = true
end

function Frontend.Popup.Close(): ()
	local BGTweenInfo = TweenInfo.new(Var.AnimationSpeed * 0.65, Enum.EasingStyle.Cubic)

	local Box = nil
	local boxOk, boxResult = pcall(function()
		return Var.MainFrame.administer.MessageBox
	end)
	if boxOk then
		Box = boxResult
	end

	if Box then
		Box.Visible = false
		Box.GroupTransparency = 0
		Box.Size = MessageBoxCanonicalSize
	end
	Var.PopupOpen = false

	task.spawn(function()
		pcall(function()
			for descendant, original in Frontend.Popup.OriginalStates do
				if descendant then
					Var.Services.TweenService
						:Create(descendant, BGTweenInfo, {
							Size = original.Size,
							Position = original.Position,
							BackgroundColor3 = original.Color,
							AnchorPoint = original.AnchorPoint,
						})
						:Play()
				end
			end
		end)

		if Box then
			local cs = MessageBoxCanonicalSize
			local closeDuration = Var.AnimationSpeed * 0.85
			Var.Services.TweenService
				:Create(Box, TweenInfo.new(closeDuration, Enum.EasingStyle.Cubic), {
					Size = UDim2.new(
						cs.X.Scale * 0.35,
						math.floor(cs.X.Offset * 0.35),
						cs.Y.Scale * 0.35,
						math.floor(cs.Y.Offset * 0.35)
					),
					GroupTransparency = 1,
				})
				:Play()

			task.wait(closeDuration)
			Box.Size = MessageBoxCanonicalSize
			Box.GroupTransparency = 0
		end
	end)
end

local MessageBox = Var.MainFrame.administer.MessageBox
local MessageBoxCanonicalSize = nil
local ButtonOneOriginalPos = MessageBox.Button1.Position
local PopupButtons = {}

function Frontend.Popup.new(
	App: {
		Name: string,
		Subheader: string,
		Icon: string,
	},

	Icons: {
		Primary: string,
		SubIcon: string?,
	},

	Header: string,
	BodyText: string,

	Options: {
		{
			Text: string,
			Icon: string,
			Callback: (Close: () -> (), TextInputChoices: { string? }) -> (),
		}
	},

	TextInputs: {
		{
			HeaderText: string,
		}
	}
): ()
	if Options ~= nil and #Options > 2 then
		Utilities.Logging.Warn("Popups may not have more than two buttons")

		return { false, "Popups may not have more than two buttons" }
	end

	if TextInputs ~= nil and #TextInputs > 2 then
		Utilities.Logging.Warn("Popups may not have more than two text inputs.")

		return { false, "Popups may not have more than two text inputs." }
	end

	if Var.PopupOpen then
		Utilities.Logging.Warn("A popup is already open and must be closed before a new one is opened.")

		return { false, "Only one popup may be open at a time." }
	end

	for _, Signal in PopupButtons do
		Signal:Disconnect()
	end

	for Num = 1, 2 do
		local Input = MessageBox.TextInputs[Num].Box

		Input.Text = ""
		Input.ClearTextOnFocus = false
	end

	local ClosePopup = Frontend.Popup.Close

	MessageBox.Header.HeaderLabel.Text = `<b>{App.Name}</b>\n{App.Subheader ~= nil and App.Subheader or Header}`
	MessageBox.Header.AppIcon.Image = App.Icon

	MessageBox.PrimaryText.Text = Header
	MessageBox.SubText.Text = BodyText

	MessageBox.AppLogo.LogoImage.Image = Icons.Primary or App.Icon
	MessageBox.SubIcon.Image = Icons.SubIcon and Icons.SubIcon or ""

	MessageBox.AppLogo.LogoImage.Position = not Icons.SubIcon and UDim2.fromScale(0.5, 0.5)
		or UDim2.fromScale(0.047, 0.149)
	MessageBox.AppLogo.LogoImage.AnchorPoint = not Icons.SubIcon and Vector2.new(0.5, 0.5) or Vector2.new(0, 0)

	MessageBox.Button1.Label.Text = Options[1].Text
	MessageBox.Button1.Icon.Image = Options[1].Icon
	PopupButtons[1] = MessageBox.Button1.MouseButton1Click:Connect(function()
		local cbOk, cbErr = pcall(function()
			Options[1].Callback(ClosePopup, {
				MessageBox.TextInputs[1].Box.Text,
				MessageBox.TextInputs[2].Box.Text,
			})
		end)
		if not cbOk then
			Utilities.Logging.Warn("[Popup] Button1 callback error:", tostring(cbErr))
			ClosePopup()
		end
	end)

	xpcall(function()
		MessageBox.Button2.Label.Text = Options[2].Text
		MessageBox.Button2.Icon.Image = Options[2].Icon
		PopupButtons[2] = MessageBox.Button2.MouseButton1Click:Connect(function()
			Options[2].Callback(ClosePopup, {
				MessageBox.TextInputs[1].Box.Text,
				MessageBox.TextInputs[2].Box.Text,
			})
		end)

		MessageBox.Button2.Visible = true
		MessageBox.Button1.AnchorPoint = Vector2.zero
		MessageBox.Button1.Position = ButtonOneOriginalPos
	end, function()

		MessageBox.Button2.Visible = false
		MessageBox.Button1.AnchorPoint = Vector2.new(0.5, 0)
		MessageBox.Button1.Position = UDim2.fromScale(0.5, MessageBox.Button1.Position.Y.Scale)
	end)

	if TextInputs == nil then
		MessageBox.SubText.TextYAlignment = Enum.TextYAlignment.Center

		for _, Box in MessageBox.TextInputs:GetChildren() do
			if Box:IsA("Frame") then
				Box.Visible = false
			end
		end
	else
		MessageBox.SubText.TextYAlignment = Enum.TextYAlignment.Top

		for Num, Input in TextInputs do
			MessageBox.TextInputs[Num].Visible = true
			MessageBox.TextInputs[Num].Label.Text = Input.HeaderText
		end
	end

	Frontend.Popup.Open()

	MessageBox.Visible = true
end

function Frontend.SwapAppBasic(NewFrame: Frame | CanvasGroup, NewConfig: { Name: string, Icon: string })
	if NewFrame.Name == Var.ActivePage.Name then
		return
	end

	local OGFramePos, OGFrameAP, NewFramePos, NewFrameAP =
		Var.ActivePage.Position, Var.ActivePage.AnchorPoint, NewFrame.Position, NewFrame.AnchorPoint
	local TInfo = TweenInfo.new(Var.AnimationSpeed * 0.75, Enum.EasingStyle.Quart)

	NewFrame.Visible = true

	NewFrame.Position = UDim2.new(1, 0, 0.5, 0)
	NewFrame.AnchorPoint = Vector2.new(0.5, 0)

	local x = Var.Services.TweenService:Create(NewFrame, TInfo, { Position = NewFramePos, AnchorPoint = NewFrameAP })
	Var.Services.TweenService
		:Create(Var.ActivePage, TInfo, { Position = UDim2.new(-1, 0, 0.5, 0), AnchorPoint = Vector2.new(0.5, 0) })
		:Play()

	x:Play()
	x.Completed:Wait()

	Var.ActivePage.Position = OGFramePos
	Var.ActivePage.AnchorPoint = OGFrameAP
	Var.ActivePage.Visible = false

	Var.ActivePage = NewFrame

	repeat
		task.wait()
	until Var.MainFrame:FindFirstChild("Header")

	pcall(function()
		Var.MainFrame.Header.Mark.HeaderTitle.Text = "<b>Administer</b>"
		Var.MainFrame.Header.Mark.HeaderSubapp.Text = NewConfig.Name
		Var.MainFrame.Header.Mark.AppLogo.AppIcon.Image = NewConfig.Icon
		Var.MainFrame.Header.Mark.Logo.Image = Utilities.Icon("administer")

		Var.Services.TweenService:Create(NewFrame, TInfo, { Position = NewFramePos, AnchorPoint = NewFrameAP }):Play()
	end)
end

function Frontend.SwapApps(AppConfig: Types.ButtonConfig, Clicked: number)
	local NewFrame

	Ready = true

	if typeof(AppConfig) == "Instance" then
		NewFrame = AppConfig
	elseif Clicked == 0 then
		NewFrame = AppConfig.MainButtonFrame
	else
		NewFrame = AppConfig.SubIcons[Clicked].Frame
	end

	if NewFrame.Name == Var.ActivePage.Name then
		return
	end

	local OGFramePos, OGFrameAP, NewFramePos, NewFrameAP =
		Var.ActivePage.Position, Var.ActivePage.AnchorPoint, NewFrame.Position, NewFrame.AnchorPoint
	local TInfo = TweenInfo.new(Var.AnimationSpeed * 0.75, Enum.EasingStyle.Quart)

	NewFrame.Visible = true

	NewFrame.Position = UDim2.new(1, 0, 0.5, 0)
	NewFrame.AnchorPoint = Vector2.new(0.5, 0)

	local x = Var.Services.TweenService:Create(NewFrame, TInfo, { Position = NewFramePos, AnchorPoint = NewFrameAP })
	Var.Services.TweenService
		:Create(Var.ActivePage, TInfo, { Position = UDim2.new(-1, 0, 0.5, 0), AnchorPoint = Vector2.new(0.5, 0) })
		:Play()

	x:Play()
	x.Completed:Wait()

	Var.ActivePage.Position = OGFramePos
	Var.ActivePage.AnchorPoint = OGFrameAP
	Var.ActivePage.Visible = false

	Var.ActivePage = NewFrame

	repeat
		task.wait()
	until Var.MainFrame:FindFirstChild("Header")

	xpcall(function()
		Var.MainFrame.Header.Mark.HeaderTitle.Text = Clicked ~= 0 and AppConfig.AppName or "Administer"
		Var.MainFrame.Header.Mark.HeaderSubapp.Text = Clicked == 0 and AppConfig.AppName
			or AppConfig.SubIcons[Clicked].Name
		Var.MainFrame.Header.Mark.AppLogo.AppIcon.Image = AppConfig.Icon
		Var.MainFrame.Header.Mark.Logo.Image = Clicked == 0 and Utilities.Icon("administer")
			or AppConfig.SubIcons[Clicked].Icon

		Var.Services.TweenService:Create(NewFrame, TInfo, { Position = NewFramePos, AnchorPoint = NewFrameAP }):Play()
	end, function()
	end)
end

function Frontend.InitGestureBar()
	Utilities.Logging.Warn("attempt to use deprecated method (Frontend.InitGestureBar)")
	return { false, "This method is deprecated" }
end

local MinX, MinY = -350, -300
local MaxX, MaxY = workspace.Camera.ViewportSize.X, workspace.Camera.ViewportSize.Y
local OverlayConnections: { [string]: RBXScriptConnection } = {}

function Frontend.SpawnOverlay(Frame: Frame | CanvasGroup)
	local Speed = Var.AnimationSpeed
	local ButtonsOpen = false
	local MovementConnection: RBXScriptConnection

	local OverlayClone = Var.AdministerRoot.AdmOverlays.Template:Clone()

	OverlayClone.Parent = Var.AdministerRoot.AdmOverlays
	OverlayClone.Name = `{Frame.Name}_Overlay`

	Frame:GetPropertyChangedSignal("Size"):Connect(function()
		OverlayClone.Size = Frame.Size
	end)

	Frame:GetPropertyChangedSignal("Position"):Connect(function()
		OverlayClone.Position = Frame.Position
	end)

	Frame:GetPropertyChangedSignal("AnchorPoint"):Connect(function()
		OverlayClone.AnchorPoint = Frame.AnchorPoint
	end)

	Frame:GetPropertyChangedSignal("BackgroundTransparency"):Connect(function()
		OverlayClone.Grabber.BackgroundTransparency = Frame.BackgroundTransparency
	end)

	Frame:GetPropertyChangedSignal("GroupTransparency"):Connect(function()
		OverlayClone.Grabber.BackgroundTransparency = Frame.GroupTransparency
		OverlayClone.Visible = OverlayClone.Grabber.BackgroundTransparency ~= 1
	end)

	if Frame:FindFirstChild("UISizeConstraint") then
		local SizeConstraint = Frame:FindFirstChild("UISizeConstraint"):Clone()

		SizeConstraint.Parent = OverlayClone
	end

	OverlayClone.AnchorPoint = Frame.AnchorPoint
	OverlayClone.Position = Frame.Position
	OverlayClone.Size = Frame.Size

	Var.Services.TweenService
		:Create(OverlayClone.Grabber, TweenInfo.new(Var.AnimationSpeed * 0.3), {
			BackgroundTransparency = (
				Frame.GroupTransparency ~= nil and Frame.GroupTransparency or Frame.BackgroundTransparency
			),
		})
		:Play()

	task.delay(Var.AnimationSpeed * 0.3, function()
		OverlayClone.Visible = false
	end)

	OverlayClone.Visible = true

	local function HideButtons()
		local Controls = OverlayClone.Grabber.Controls

		ButtonsOpen = false

		Var.Services.TweenService
			:Create(OverlayClone.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				Position = UDim2.fromScale(0.5, 1.02),
				Size = UDim2.fromOffset(150, 6),
			})
			:Play()

		Var.Services.TweenService
			:Create(Controls, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				GroupTransparency = 1,
				Size = UDim2.fromScale(0.704, 2.5),
				Position = UDim2.fromScale(0, 0),
			})
			:Play()
	end

	local function ShowButtons()
		local Controls = OverlayClone.Grabber.Controls

		if ButtonsOpen then
			return
		end
		if OverlayClone.Visible == false then
			return
		end

		ButtonsOpen = true

		Var.Services.TweenService
			:Create(OverlayClone.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				Position = UDim2.fromScale(0.55, 1.02),
				Size = UDim2.fromOffset(105, 6),
			})
			:Play()

		Controls.Visible = true
		Controls.GroupTransparency = 1
		Controls.Size = UDim2.fromScale(0.704, 2.5)
		Controls.Position = UDim2.fromScale(0, 0)

		Var.Services.TweenService
			:Create(Controls, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				GroupTransparency = 0,
				Size = UDim2.fromScale(0.704, 3.5),
				Position = UDim2.fromScale(-0.85, 0.5),
			})
			:Play()
	end

	local LeftOver = OverlayClone.GrabberLeft.MouseEnter:Connect(ShowButtons)
	local LeftLeave = OverlayClone.GrabberLeft.MouseLeave:Connect(function()
		task.delay(3, HideButtons)
	end)

	local Grabber = OverlayClone.Grabber.RealGrabber
	local GrabMove, InputEnded: RBXScriptSignal

	Grabber.MouseEnter:Connect(function()
		if ButtonsOpen then
			return
		end

		Var.Services.TweenService
			:Create(OverlayClone.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				Size = UDim2.fromOffset(165, 15),
				BackgroundColor3 = Color3.fromRGB(185, 185, 185),
			})
			:Play()
	end)

	Grabber.MouseLeave:Connect(function()
		Var.Services.TweenService
			:Create(OverlayClone.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				Size = UDim2.fromOffset(150, 6),
				BackgroundColor3 = Color3.new(1, 1, 1),
			})
			:Play()
	end)

	Grabber.InputBegan:Connect(function(Input)
		if Input.UserInputType ~= Enum.UserInputType.MouseButton1 then
			return
		end
		local StartPos, StartPanelPos = Input.Position, Var.MainFrame.Position

		GrabMove = Var.Services.UserInputService.InputChanged:Connect(function(MoveInput)
			if MoveInput.UserInputType == Enum.UserInputType.MouseMovement then
				local Delta = MoveInput.Position - StartPos

				Var.Services.TweenService
					:Create(Frame, TweenInfo.new(Var.AnimationSpeed * 0.2, Enum.EasingStyle.Quart), {
						Position = UDim2.new(
							StartPanelPos.X.Scale,
							StartPanelPos.X.Offset + Delta.X,
							StartPanelPos.Y.Scale,
							StartPanelPos.Y.Offset + Delta.Y
						),
					})
					:Play()
			end
		end)
	end)

	Grabber.InputEnded:Connect(function()
		repeat
			task.wait()
		until not Var.Services.UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)

		if GrabMove then
			GrabMove:Disconnect()
		end

		Var.Services.TweenService
			:Create(OverlayClone.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
				Size = UDim2.fromOffset(150, 6),
				BackgroundColor3 = Color3.new(1, 1, 1),
			})
			:Play()
	end)

	local function GripAnimation(Type: "Release" | "Grip" | "Hover", Axis: "X" | "Y" | "XY")
		if Type == "Release" then
			Var.Services.TweenService
				:Create(OverlayClone.CornerGripper.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
					Size = UDim2.fromOffset(50, 50),
				})
				:Play()

			if MovementConnection then
				repeat
					task.wait()
				until not Var.Services.UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)

				MovementConnection:Disconnect()
			end
		elseif Type == "Grip" then
			Var.Services.TweenService
				:Create(OverlayClone.CornerGripper.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
					Size = UDim2.fromOffset(
						Axis == "X" and 75 or Axis == "XY" and 60 or 45,
						Axis == "Y" and 75 or Axis == "XY" and 60 or 45
					),
				})
				:Play()
		elseif Type == "Hover" then
			Var.Services.TweenService
				:Create(OverlayClone.CornerGripper.Grabber, TweenInfo.new(Speed * 0.5, Enum.EasingStyle.Quart), {
					Size = UDim2.fromOffset(
						Axis == "X" and 70 or Axis == "XY" and 60 or 45,
						Axis == "Y" and 70 or Axis == "XY" and 60 or 45
					),
				})
				:Play()
		end
	end

	local RecentClick = false
	local function DoResize(Input, Axis)
		if MovementConnection then
			MovementConnection:Disconnect()
		end
		if InputEnded then
			InputEnded:Disconnect()
		end

		local StartPos = Var.Services.UserInputService:GetMouseLocation()
		local StartSize = Frame.Size

		if RecentClick then
			Frontend.Open(true)

			return
		else
			RecentClick = true
			task.delay(0.2, function()
				RecentClick = false
			end)
		end

		MovementConnection = Var.Services.UserInputService.InputChanged:Connect(function(MoveInput)
			local Size

			if MoveInput.UserInputType == Enum.UserInputType.MouseMovement then
				local MousePos = Var.Services.UserInputService:GetMouseLocation()
				local Delta = MousePos - StartPos

				local NewX = StartSize.X.Offset + Delta.X * 1.5
				local NewY = StartSize.Y.Offset + Delta.Y * 1.5

				if Axis == "X" then
					Size = UDim2.new(StartSize.X.Scale, NewX, StartSize.Y.Scale, StartSize.Y.Offset)
				elseif Axis == "Y" then
					Size = UDim2.new(StartSize.X.Scale, StartSize.X.Offset, StartSize.Y.Scale, NewY)
				elseif Axis == "XY" then
					Size = UDim2.new(StartSize.X.Scale, NewX, StartSize.Y.Scale, NewY)
				end

				Var.Services.TweenService
					:Create(Frame, TweenInfo.new(Var.AnimationSpeed * 0.2, Enum.EasingStyle.Quart), {
						Size = Size,
					})
					:Play()
			end
		end)

		InputEnded = Var.Services.UserInputService.InputEnded:Connect(function(EndInput)
			warn(EndInput)
			if EndInput.UserInputType == Enum.UserInputType.MouseButton1 then
				if MovementConnection then
					MovementConnection:Disconnect()

					repeat
						task.wait()
					until not Var.Services.UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)
				end
				if InputEnded then
					InputEnded:Disconnect()
				end
				GripAnimation("Release", Axis)
			end
		end)
	end

	local function ToggleGripperVisibility(ForceState)
		local Opacity = Utilities.GetSetting("GripperIdleOpacity")
		local Idle = Opacity == "visible" and 0 or Opacity == "faint" and 0.5 or 1

		Var.Services.TweenService
			:Create(
				OverlayClone.CornerGripper.Grabber,
				TweenInfo.new(
					Speed * 0.3,
					Enum.EasingStyle.Quart,
					Enum.EasingDirection.In,
					0,
					false,
					ForceState == false and 2 or 0
				),
				{ ImageTransparency = ForceState and 0 or Idle }
			)
			:Play()
	end

	ToggleGripperVisibility()

	OverlayClone.CornerGripper.Trigger.MouseEnter:Connect(function()
		ToggleGripperVisibility(true)
		GripAnimation("Hover", "XY")
	end)

	OverlayClone.CornerGripper.Trigger.MouseLeave:Connect(function()
		ToggleGripperVisibility(false)
		GripAnimation("Release", "XY")
	end)

	OverlayClone.CornerGripper.Trigger.InputBegan:Connect(function(Input)
		if Input.UserInputType == Enum.UserInputType.MouseButton1 then
			GripAnimation("Grip", "XY")
			DoResize(Input, "XY")
		end
	end)

	OverlayClone.CornerGripper.TriggerHoriz.MouseEnter:Connect(function()
		ToggleGripperVisibility(true)
		GripAnimation("Hover", "X")
	end)

	OverlayClone.CornerGripper.TriggerHoriz.MouseLeave:Connect(function()
		ToggleGripperVisibility(false)
		GripAnimation("Release", "X")
	end)

	OverlayClone.CornerGripper.TriggerHoriz.InputBegan:Connect(function(Input)
		if Input.UserInputType == Enum.UserInputType.MouseButton1 then
			GripAnimation("Grip", "X")
			DoResize(Input, "X")
		end
	end)

	OverlayClone.CornerGripper.TriggerVert.MouseEnter:Connect(function()
		ToggleGripperVisibility(true)
		GripAnimation("Hover", "Y")
	end)

	OverlayClone.CornerGripper.TriggerVert.MouseLeave:Connect(function()
		ToggleGripperVisibility(false)
		GripAnimation("Release", "Y")
	end)

	OverlayClone.CornerGripper.TriggerVert.InputBegan:Connect(function(Input)
		if Input.UserInputType == Enum.UserInputType.MouseButton1 then
			GripAnimation("Grip", "Y")
			DoResize(Input, "Y")
		end
	end)

	OverlayConnections[Frame.Name] = {}

	for _, Conn in
		{
			Close = OverlayClone.Grabber.Controls.Close.MouseButton1Click:Connect(function()
				Frontend.Close(Frame)
			end),

			Expand = OverlayClone.Grabber.Controls.Expand.MouseButton1Click:Connect(function()
				Frontend.ToggleFullscreen(false, Frame)
			end),

			ExpandFixGripper = Frame:GetAttributeChangedSignal("IsFullScreen"):Connect(function()
				local IsFullScreen = Frame:GetAttribute("IsFullScreen")
				Var.Services.TweenService
					:Create(OverlayClone.CornerGripper.Grabber, TweenInfo.new(Var.AnimationSpeed * 0.3), {
						ImageTransparency = IsFullScreen and 1 or 0,
					})
					:Play()

				OverlayClone.CornerGripper.TriggerVert.Visible = not IsFullScreen
				OverlayClone.CornerGripper.TriggerHoriz.Visible = not IsFullScreen
				OverlayClone.CornerGripper.Trigger.Visible = not IsFullScreen

				if IsFullScreen then
					local Trigger = Instance.new("TextButton")

					Trigger.Parent = Frame
					Trigger.Text = ""

					Trigger.Size = UDim2.fromOffset(150, 15)

					Trigger.AnchorPoint = Vector2.new(0.5, 1)
					Trigger.Position = UDim2.new(0.5, 0, 1, -10)
				end
			end),

			Shrink = OverlayClone.Grabber.Controls.Minimize.MouseButton1Click:Connect(function()
				print("shrink TODO")
			end),
		}
	do
		table.insert(OverlayConnections[Frame.Name], Conn)
	end
end

function Frontend.RegisterPanelKeybind()
	local currentKeys, Debounce = {}, false

	local targetSettings = {
		"PanelKeybind",
		"PanelFullscreenKeybind",
		"AppDrawerKeybind",
	}
	local keybinds = Utilities.GetSettings(targetSettings)

	local openKeybind = keybinds["PanelKeybind"]
	local openChanged = Utilities.GetSettingChanged("PanelKeybind")

	local ExpandKeybind = keybinds["PanelFullscreenKeybind"]
	local expandChanged = Utilities.GetSettingChanged("PanelFullscreenKeybind")

	local DrawerKeybind = keybinds["AppDrawerKeybind"]
	local DrawerChanged = Utilities.GetSettingChanged("AppDrawerKeybind")

	local loadedSettings: RemoteEvent = Var.Remotes:FindFirstChild("SettingsLoaded")

	loadedSettings.OnClientEvent:Connect(function()
		keybinds = Utilities.GetSettings(targetSettings)

		openKeybind = keybinds["PanelKeybind"]
		ExpandKeybind = keybinds["PanelFullscreenKeybind"]
		DrawerKeybind = keybinds["AppDrawerKeybind"]
	end)

	openChanged.OnClientEvent:Connect(function(newValue)
		openKeybind = newValue
	end)

	expandChanged.OnClientEvent:Connect(function(newValue)
		ExpandKeybind = newValue
	end)

	DrawerChanged.OnClientEvent:Connect(function(newValue)
		DrawerKeybind = newValue
	end)

	Var.Services.UserInputService.InputBegan:Connect(function(KeyCode, IsGameProc)
		if IsGameProc then
			return
		end

		if KeyCode.KeyCode == Enum.KeyCode.Unknown then
			return
		end

		table.insert(currentKeys, KeyCode.KeyCode)
	end)

	Var.Services.UserInputService.InputEnded:Connect(function(KeyCode, IsGameProc)
		if IsGameProc then
			return
		end

		if KeyCode.KeyCode == currentKeys[1] then
			local commaSeparated = {}

			for i, v in currentKeys do
				table.insert(commaSeparated, v.Name)
			end

			commaSeparated = table.concat(commaSeparated, ",")
			currentKeys = {}

			if commaSeparated == ExpandKeybind then
				if Debounce then
					return
				end
				Debounce = true

				if not Var.IsOpen then
					Frontend.Open(true)
				end

				Frontend.ToggleFullscreen(false, Var.MainFrame)

				Debounce = false
			elseif commaSeparated == openKeybind then
				if Debounce then
					return
				end
				Debounce = true

				if Var.IsOpen then
					Frontend.Close(false, true)
				else
					Frontend.Open(true)
				end

				Debounce = false
			elseif commaSeparated == DrawerKeybind then
				Frontend.Drawer.Open()
			end
		end
	end)
end

function Frontend.AddButtonAnimation(Button: TextButton | ImageButton)
	local Tween = TweenInfo.new(Var.AnimationSpeed * 0.3, Enum.EasingStyle.Quart)
	local BGChanged

	local UICorner = Button:FindFirstChildWhichIsA("UICorner") or Instance.new("UICorner")
	local OriginalCorner = UICorner.CornerRadius
	local OriginalColor = Button.BackgroundColor3

	Button.AutoButtonColor = false

	UICorner.Parent = Button

	local function Lighten(color, amount)
		local h, s, v = color:ToHSV()

		v = math.clamp(v + amount, 0, 1)

		return Color3.fromHSV(h, s, v)
	end

	Button.MouseEnter:Connect(function()
		local NewBorder = Instance.new("UIStroke")

		NewBorder.Color = Button.BackgroundColor3
		NewBorder.Transparency = Button.BackgroundTransparency
		NewBorder.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
		NewBorder.Thickness = 0

		NewBorder.Name = "ButtonAnimBorder"
		NewBorder.Parent = Button

		BGChanged = Button:GetPropertyChangedSignal("BackgroundColor3"):Connect(function()
			NewBorder.Color = Button.BackgroundColor3
		end)

		Var.Services.TweenService
			:Create(UICorner, Tween, {
				CornerRadius = OriginalCorner + UDim.new(0, 4),
			})
			:Play()

		Var.Services.TweenService
			:Create(Button.ButtonAnimBorder, Tween, {
				Thickness = 3,
			})
			:Play()

		Var.Services.TweenService
			:Create(Button, Tween, {
				BackgroundColor3 = Lighten(Button.BackgroundColor3, 0.2),
			})
			:Play()

		script.Parent.Parent.Assets.SelectSound:Play()
	end)

	Button.MouseLeave:Connect(function()
		if Button:FindFirstChild("ButtonAnimBorder") then
			task.defer(function()
				BGChanged:Disconnect()

				local BorderGone = Var.Services.TweenService:Create(Button.ButtonAnimBorder, Tween, {
					Thickness = 0,
				})

				BorderGone:Play()
				BorderGone.Completed:Wait()

				local border = Button:FindFirstChild("ButtonAnimBorder")
				if border then
					border:Destroy()
				end
			end)
		end

		Var.Services.TweenService
			:Create(Button, Tween, {
				BackgroundColor3 = OriginalColor,
			})
			:Play()

		Var.Services.TweenService
			:Create(UICorner, Tween, {
				CornerRadius = OriginalCorner,
			})
			:Play()
	end)

	Button.MouseButton1Click:Connect(function()
		script.Parent.Parent.Assets.ClickSound:Play()
		script.Parent.Parent.Assets.ClickHaptic:Play()

		Ripple(Button, game.Players.LocalPlayer:GetMouse(), Var.AnimationSpeed * 0.4, Color3.fromRGB(255, 255, 255))
	end)

	Button.MouseButton2Click:Connect(function()
		script.Parent.Parent.Assets.ClickSound:Play()

		Ripple(Button, game.Players.LocalPlayer:GetMouse(), Var.AnimationSpeed * 0.4, Color3.fromRGB(255, 255, 255))
	end)
end

function Frontend.PrepTheme()
	local Dark = require(script.Parent.Parent.Assets.Themes.DefaultDark)

	local ForceSimilarity = Utilities.GetSetting("ThemeForceSimilarity") == true
	local Debug = Utilities.GetSetting("ThemeDebug") == true
	local Threshold = Utilities.GetSetting("ThemeSimilarityThreshold") or 12

	local function ColorDistance(a, b)
		if not a or not b then
			return math.huge
		end
		local DistanceRed = (a.R - b.R) * 255
		local DistanceGreen = (a.G - b.G) * 255
		local DistanceBlue = (a.B - b.B) * 255

		return math.sqrt(DistanceRed * DistanceRed + DistanceGreen * DistanceGreen + DistanceBlue * DistanceBlue)
	end

	local function FindClosestInGroup(Color, Group, GroupName)
		local BestName, BestColor, BestDistance = nil, nil, math.huge

		for ColorName, Data in pairs(Group or {}) do
			local cand = (type(Data) == "table" and Data.Color) or (typeof(Data) == "Color3" and Data)
			if not cand then
				continue
			end

			local success, _ = xpcall(function()
				local d = ColorDistance(Color, cand)

				if d < BestDistance then
					BestName = (GroupName and (GroupName .. "." .. tostring(ColorName))) or tostring(ColorName)
					BestColor = cand
					BestDistance = d
				end
			end, Utilities.Logging.Warn)
		end

		return BestName, BestColor, BestDistance
	end

	local function FindClosestAcrossPriority(Color, Groups)
		if not Color then
			return nil, nil, math.huge
		end
		local Name, BestColor, Distance = nil, nil, math.huge

		for _, g in Groups do
			local n, c, d = FindClosestInGroup(Color, g.tbl, g.Name)

			if c and d < Distance then
				Name, BestColor, Distance = n, c, d
			end
		end

		return Name, BestColor, Distance
	end

	local function DebugLabel(Descendant, ColorName)
		if Debug then
			local NewTL = Instance.new("TextLabel")

			NewTL.Size = UDim2.fromScale(1, 1)
			NewTL.Parent = Descendant
			NewTL.BackgroundTransparency = 0.25
			NewTL.Text = ColorName
		end
	end

	local IconIndex = {}
	for Name, Icon in Var.Icons do
		if Name == "administer" then
			continue
		end

		IconIndex[Icon] = Icon
	end

	local function Process(Descendant: GuiObject)
		if Descendant:GetAttribute("_AdmStyleText") or Descendant:GetAttribute("_AdmStyleBackground") then
			return
		end

		if Descendant:IsA("TextLabel") or Descendant:IsA("TextButton") or Descendant:IsA("TextBox") then
			local Found = false

			for ColorName, Data in Dark.Colors.Text do
				local cand = (type(Data) == "table" and Data.Color) or (typeof(Data) == "Color3" and Data)

				if cand and Descendant.TextColor3 == cand then
					Found = ColorName

					break
				end
			end

			if not Found and ForceSimilarity then
				local ColorName, Color, Distance = FindClosestInGroup(Descendant.TextColor3, Dark.Colors.Text, "Text")

				if Color and Distance <= (Threshold * 2) then
					Descendant.TextColor3 = Color
					Found = ColorName
				else
				end
			end

			DebugLabel(Descendant, Found or "NoMatch")

			if Found then
				Descendant:SetAttribute("_AdmStyleText", Found)
			end
		end

		if Descendant:IsA("ImageLabel") or Descendant:IsA("ImageButton") then
			if IconIndex[Descendant.Image:match("%d+$")] then
				Descendant.ImageColor3 = Dark.Colors.Text.Primary.Color

				Descendant:SetAttribute("_AdmStyleText", "Primary")
				Descendant:SetAttribute("_AdmIsIcon", true)

				return
			else
				Descendant:SetAttribute("_AdmIsIcon", false)
			end

			if ForceSimilarity then
				local Name, DataType, Distance = FindClosestAcrossPriority(Descendant.ImageColor3, {
					{ Name = "Text", tbl = Dark.Colors.Text },
					{ Name = "Colors", tbl = Dark.Colors.Colors },
					{ Name = "Buttons", tbl = Dark.Colors.Buttons },
				})

				if DataType and Distance <= Threshold then
					Descendant.ImageColor3 = DataType
					Descendant:SetAttribute("_AdmStyleText", string.gsub(Name, "Text.", ""))
				end
			end
		end

		if Descendant:IsA("TextButton") or Descendant:IsA("ImageButton") then
			if Descendant.BackgroundTransparency ~= 1 then
				local Found = false

				for ColorName, Data in Dark.Colors.Buttons do
					local DataType = (type(Data) == "table" and Data.Color) or (typeof(Data) == "Color3" and Data)
					if DataType and Descendant.BackgroundColor3 == DataType then
						Found = ColorName
						break
					end
				end

				if not Found and ForceSimilarity then
					local Name, DataType, Distance =
						FindClosestInGroup(Descendant.BackgroundColor3, Dark.Colors.Buttons, "Buttons")
					if DataType and Distance <= Threshold then
						Descendant.BackgroundColor3 = DataType

						Found = Name
					end
				end

				DebugLabel(Descendant, Found or "NoMatch")

				if Found then
					Descendant:SetAttribute("_AdmStyleBackground", Found)
				end
			end
		end

		if Descendant:IsA("GuiObject") then
			if Descendant.BackgroundTransparency ~= 1 then
				local Found = false

				for ColorName, Data in Dark.Colors.Background do
					local DataType = (type(Data) == "table" and Data.Color) or (typeof(Data) == "Color3" and Data)

					if DataType and Descendant.BackgroundColor3 == DataType then
						Found = ColorName

						break
					end
				end

				if not Found and ForceSimilarity then
					local Name, Type, Distance =
						FindClosestInGroup(Descendant.BackgroundColor3, Dark.Colors.Background, "Background")
					if Type and Distance <= Threshold then
						Descendant.BackgroundColor3 = Type

						Found = Name
					end
				end

				DebugLabel(Descendant, Found or "NoMatch")

				if Found then
					Descendant:SetAttribute("_AdmStyleBackground", Found)
				end
			end
		end
	end

	for _, Descendant in Var.MainFrame.Parent:GetDescendants() do
		Process(Descendant)
	end

	Process(Var.MainFrame)

	if Var.ThemeAddedEvent then
		Var.ThemeAddedEvent:Disconnect()
	end

	Var.ThemeAddedEvent = Var.MainFrame.Parent.DescendantAdded:Connect(function(Child)
		if not Child:IsA("GuiObject") then
			return
		end

		Process(Child)
	end)
end

function Frontend.LoadTheme(ThemeTable)
	Utilities.Logging.Print(`Loading theme`, ThemeTable)

	Var.UseAcrylic = ThemeTable.EnableAcrylic
	if ThemeTable.EnableAcrylic then
		require(Libraries.Neon):BindFrame(Var.MainFrame, {
			Transparency = 0.95,
			BrickColor = BrickColor.new("Institutional white"),
		})

		if not game.Lighting:FindFirstChild("AdministerAcrylic") then
			local NewEffect = Instance.new("DepthOfFieldEffect")
			NewEffect.FarIntensity = 0
			NewEffect.FocusDistance = 51.6
			NewEffect.InFocusRadius = 50
			NewEffect.NearIntensity = 1

			NewEffect.Parent = game.Lighting
			NewEffect.Name = "AdministerAcrylic"
		end
	else
		require(Libraries.Neon):UnbindFrame(Var.MainFrame)
	end

	local function Style(Descendant: GuiObject)
		if Descendant:IsA("GuiObject") then
			if Descendant:GetAttribute("_AdmStyleText") then
				for Name, Color in ThemeTable.Colors.Text do
					if Name == Descendant:GetAttribute("_AdmStyleText") then
						if Descendant:IsA("TextBox") or Descendant:IsA("TextLabel") then
							Descendant.TextColor3 = Color.Color

							Descendant.FontFace = ThemeTable.General.Fonts[Name]

							if Descendant.TextTransparency ~= 1 then
								Descendant.TextTransparency = Color.Transparency
							end
						elseif Descendant:IsA("ImageLabel") or Descendant:IsA("ImageButton") then
							if Descendant:GetAttribute("_AdmIsIcon") or ThemeTable.ForceStyleImages == true then
								Descendant.ImageColor3 = Color.Color

								if Descendant.ImageTransparency ~= 1 then
									Descendant.ImageTransparency = Color.Transparency
								end
							else
							end
						end
					end
				end
			end

			if Descendant:GetAttribute("_AdmStyleBackground") then
				for Name, Color in ThemeTable.Colors.Background do
					if Name == Descendant:GetAttribute("_AdmStyleBackground") then
						Descendant.BackgroundColor3 = Color.Color

						if Descendant.BackgroundTransparency ~= 1 then
							Descendant.BackgroundTransparency = Color.Transparency
						end
					end
				end

				for Name, Color in ThemeTable.Colors.Colors do
					if Name == Descendant:GetAttribute("_AdmStyleBackground") then
						Descendant.BackgroundColor3 = Color.Color

						if Descendant.BackgroundTransparency ~= 1 then
							Descendant.BackgroundTransparency = Color.Transparency
						end
					end
				end

				for Name, Color in ThemeTable.Colors.Buttons do
					if Name == Descendant:GetAttribute("_AdmStyleBackground") then
						Descendant.BackgroundColor3 = Color.Color

						if Descendant.BackgroundTransparency ~= 1 then
							Descendant.BackgroundTransparency = Color.Transparency
						end
					end
				end
			end
		elseif Descendant:IsA("UICorner") then
			for _, Overrides in ThemeTable.General.RoundingOverrides do
				if Overrides[1] == Descendant.CornerRadius then
					Descendant.CornerRadius = Overrides[2]
				end
			end
		end

		if ThemeTable.General.AdditionalProperties[Descendant.ClassName] then
			for Property, Value in ThemeTable.General.AdditionalProperties[Descendant.ClassName] do
				xpcall(function()
					Descendant[Property] = Value
				end, function()
					Utilities.Logging.Warn(
						`[ThemeValidation] prop {Descendant.ClassName}/{Property} is locked or hidden`
					)
				end)
			end
		end
	end

	Style(Var.MainFrame)

	for _, Descendant in Var.MainFrame.Parent:GetDescendants() do
		Style(Descendant)
	end

	if Var.ThemeUpdateEvent then
		Var.ThemeUpdateEvent:Disconnect()
	end

	Var.ThemeUpdateEvent = (Var.MainFrame.Parent :: CanvasGroup).DescendantAdded:Connect(function(Child)
		Style(Child)
	end)

	ThemeTable.OnStyle()
end

return Frontend


-- AjaxTiba, July 2026 (For pyxfloof)

local Root = script.Parent.Parent.Parent

local Var = require(Root.Variables)
local Frontend = require(Root.Frontend)
local Utilities = require(Root.Utilities)

local TweenService = Var.Services.TweenService
local Frames = Var.MainFrame.Welcome.SetupFull

local tour = {}
tour.Buttons = {}

function tour.GetButtons(frame: GuiObject)
	tour.Buttons = {}

	for _, v in pairs(frame:GetDescendants()) do
		if v:IsA("GuiButton") then
			table.insert(tour.Buttons, v)
		end
	end
end

function tour.ToggleButtons(buttons, enabled)
	local effected = {}
	for _, button: GuiButton in pairs(buttons) do
		if button.Interactable ~= enabled then
			table.insert(effected, button)
		end
		button.Interactable = enabled
	end

	return effected
end

function tour.highlight(button: GuiButton, labelText)
	local active = true

	local Circle = Instance.new("Frame", button)
	local UICorner = Instance.new("UICorner", Circle)

	Circle.BackgroundColor3 = Color3.new(1, 1, 1)
	Circle.Size = UDim2.new(0, 0, 0, 0)
	Circle.Position = UDim2.fromScale(0.5, 0.5)
	Circle.AnchorPoint = Vector2.new(0.5, 0.5)

	UICorner.CornerRadius = UDim.new(2, 0)

	local CircleRipple = TweenService:Create(Circle, TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {
		Size = UDim2.fromScale(1.5, 1.5),
		BackgroundTransparency = 1,
	})

	local darken = script.Circle:Clone()
	darken.Parent = Var.MainFrame.Parent
	darken.Size = UDim2.new(0, 6000, 0, 6000)
	local inset = game:GetService("GuiService"):GetGuiInset()

	local label = Instance.new("TextLabel", Var.MainFrame.Parent)
	label.Text = labelText
	label.RichText = true
	label.BackgroundTransparency = 0.5
	label.BackgroundColor3 = Color3.new(0, 0, 0)
	label.ZIndex = 6
	label.Size = UDim2.new(0, 0, 0, 0)
	label.AnchorPoint = Vector2.new(0, 0.5)
	label.TextXAlignment = Enum.TextXAlignment.Left
	label.TextColor3 = Color3.new(1, 1, 1)
	label.TextSize = 16
	label.AutomaticSize = Enum.AutomaticSize.XY
	local corner = Instance.new("UICorner", label)
	corner.CornerRadius = UDim.new(0, 8)

	local buttonAbsolutePosition = UDim2.new(0, 0, 0, 0)
	darken.Position = buttonAbsolutePosition
	darken:TweenSize(
		UDim2.new(0, button.AbsoluteSize.X * 2, 0, button.AbsoluteSize.Y * 2),
		Enum.EasingDirection.Out,
		Enum.EasingStyle.Quart,
		0.6
	)

	local updateLoop = game:GetService("RunService").RenderStepped:Connect(function()
		buttonAbsolutePosition = UDim2.new(
			0,
			button.AbsolutePosition.X + button.AbsoluteSize.X / 2 + inset.X,
			0,
			button.AbsolutePosition.Y + button.AbsoluteSize.Y / 2 + inset.Y
		)
		darken.Position = buttonAbsolutePosition
		if
			buttonAbsolutePosition.X.Offset + darken.AbsoluteSize.X
			> game.Workspace.CurrentCamera.ViewportSize.X - label.AbsoluteSize.X
		then
			label.Position = buttonAbsolutePosition - UDim2.new(0, darken.AbsoluteSize.X / 2, 0, 0)
			label.AnchorPoint = Vector2.new(1, 0.5)
		else
			label.Position = buttonAbsolutePosition + UDim2.new(0, darken.AbsoluteSize.X / 2, 0, 0)
			label.AnchorPoint = Vector2.new(0, 0.5)
		end
	end)

	button.MouseButton1Click:Once(function()
		label:Destroy()
		Circle:Destroy()
		active = false
		darken:Destroy()
		updateLoop:Disconnect()
	end)

	repeat
		CircleRipple:Play()
		CircleRipple.Completed:Wait()

		Circle.Size = UDim2.fromScale(0, 0)
		Circle.BackgroundTransparency = 0

		task.wait(0.25)
	until not active
end

function tour.Step(button: GuiButton, text: string)
	if not button:IsA("GuiButton") then
		button = button:FindFirstChildWhichIsA("GuiButton")
	end
	tour.GetButtons(Var.MainFrame)

	local effectedButtons = tour.ToggleButtons(tour.Buttons, false)
	tour.ToggleButtons({ button }, true)
	tour.highlight(button, text)

	tour.ToggleButtons(effectedButtons, true)
end

function tour.BeginTour()
	Var.IsInTutorial = true
	Var.DoHeaderEffects = true
	Var.TutorialStage = "OpenAppDrawer"

	local Header = Var.MainFrame.Header.Mark
	local apps = Var.MainFrame.AppDrawer.AppHolder.Apps

	tour.Step(
		Header.AppLogo,
		[[Lets get started by opening the App Drawer.
		Click the App Icon to continue.]]
	)

	tour.Step(
		apps:WaitForChild("Home"),
		[[First things first, let's take a look at the homepage.
		Click the Home Button to continue.]]
	)

	tour.Step(
		Var.MainFrame:WaitForChild("Home").Widget1.Edit,
		[[Here you can edit a widget to change what it shows.
		Click the Edit Button to continue.]]
	)

	tour.Step(
		Var.MainFrame:WaitForChild("Home").Widget1.Editing.Next,
		[[You can change the displayed widget by clicking the next button.
	Click the Next Button to continue.]]
	)

	task.wait(2)

	tour.Step(
		Var.MainFrame:WaitForChild("Home").Widget1.Editing.Last,
		[[You can also go back to the previous widget.
	Click the Back Button to continue.]]
	)

	task.wait(2)

	tour.Step(
		Var.MainFrame:WaitForChild("Home").Widget1.Editing.Preview,
		[[Click the widget to select it.
	Click the widget to continue.]]
	)

	task.wait(1)

	Frontend.Drawer.Open()

	tour.Step(
		apps:WaitForChild("Configuration").SubCollection.Marketplace,
		[[Open up the Marketplace by clicking Apps.
	Click Apps to continue.]]
	)

	local marketPlace = Var.MainFrame:WaitForChild("Configuration"):WaitForChild("Marketplace").MainMarketplace
	repeat
		task.wait()
	until #marketPlace.AAFeatured.TopGrid:GetChildren() > 2

	tour.Step(
		marketPlace.AAFeatured.MainHot.Stats.DownloadButton,
		[[Click the Get button to view this app.
	Click Get to continue]]
	)
	tour.Step(
		marketPlace.InstallBox.MainContent.TopHeader.Details.Downloads,
		[[Click the Install button to install this app.
	Click Install to continue]]
	)

	repeat
		task.wait()
	until Var.MainFrame.administer.MessageBox.Visible or Var.MainFrame.administer.Toast.Visible
	repeat
		task.wait()
	until not Var.MainFrame.administer.MessageBox.Visible and not Var.MainFrame.administer.Toast.Visible

	tour.Step(
		marketPlace.InstallBox.MainContent.TopHeader.Details.Votes.Likes:WaitForChild("TextButton"),
		[[And you can click here to give the app a like.
	Press Like to continue]]
	)
	tour.Step(
		marketPlace.Parent.ASidebar.Buttons.XLibrary:WaitForChild("TextButton"),
		[[You can view your installed apps here.
	Press library to continue]]
	)
	repeat
		task.wait()
	until #marketPlace.XLibrary.Content:GetChildren() > 3
	task.wait(3)

	Frontend.Drawer.Open()
	tour.Step(
		apps:WaitForChild("Configuration").SubCollection.Admins,
		[[To view and edit your games ranks, you can use the Admins menu.
	Click Admins to continue.]]
	)

	task.wait(3)
	Frontend.Drawer.Open()

	tour.Step(
		apps:WaitForChild("Configuration").SubCollection.Settings,
		[[To change any settings you can click Options.
	Click Options to continue.]]
	)

	task.wait(3)

	Frontend.SwapAppBasic(Var.MainFrame.Welcome, {
		Name = "Setup",
		Icon = Utilities.Icon("sparkles"),
	})
end

return tour