What would be considered lag friendly for a tool/spell?

Lately I have been considering how my spells in my game would appear if there was a noticeable amount of latency for client-server communication. There are different techniques, but I am looking for advice on which would be considered the best for UX.

I have a serverside script for managing the tool:

--Server
Event.OnServerEvent:Connect(function(Player, ...)
    local Char = Player.Character
    if not Char then return end
    local Tool = Char:FindFirstChildOfClass("Tool")
    if not Tool or not Tool.Enabled then return end
    local Humanoid = Char:FindFirstChildOfClass("Humanoid")
    if not (Humanoid and Humanoid.Health > 0) then return end
    local Name = Tool.Name
    local Func = ToolRegistry[Name]
    if not Func then return end
    Tool.Enabled = false
    Func(Player, Char, Tool, Humanoid) -- Yields for the cooldown period of the item
    Tool.Enabled = true
end)

One of them is playing the animation immediately if the client determines that the spell can be cast, and then disabling the spell on the client side. I would use the Tool.Enabled property to determine this. This system would do something like this:

-- Client
Tool.Activated:Connect(function()
    if not Tool.Enabled then return end
    Tool.Enabled = false
    Animation:Play()
    Event:FireServer()
end)

The issue is if for whatever reason the server denies the request before reenabling the tool which would replicate a Tool.Enabled = true to the client, the tool will be disabled forever. If I skip the Tool.Enabled = false line on the client, then if a client clicks multiple times before the fact of the server disabling the tool gets replicated, then more events are fired than need to be, using more bandwidth, and the animations are played multiple times. And if there is significant lag, the animation and the effect are out of sync.

However, if I take a different approach:

Tool.Activated:Connect(function()
    Event:FireServer()
end)
Tool:GetPropertyChangedSignal("Enabled"):Connect(function()
    if Tool.Enabled then return end
    Animation:Play()
end)

The issue is the ‘input lag’ which is supposedly very bad for UX. The client will click and will not know anything has happened at all until the server responds.

What are your thoughts on this for maximum UX?

Perhaps on the client once the tool is activated the name can change to {Tool.Name} (Pending) or {Tool.Name} (Charging) or similar, and be reset back to the original once the Enabled property replicates back to true.

Something I do is look to other games for inspiration as to how to tackle the problems. What Elemental Battlegrounds seems to do is start playing the special effect associated with the spell and finish playing it once the spell has been performed on the server and notifies the client that had happened. But that would be too complicated to implement for something that should be so simple. Like I would have to play the special effect on the local client, and then from the server fire all clients except for the user who activated it, instead of just using FireAllClients() and calling it a day.

I am looking for a solution that is reasonably good for UX but is not too complicated to implement.