My jump mechanic is frame dependent and idk why

Hello, as the title says my jumping height changes depending on the frame rate i’m playing on. I tried a lot of stuff like changing the Time.deltaTime position on every posible way and I can’t figure out why this is happening.

The jumps works by setting an initial jump force and then keep applying some force until it reaches a time limit or the player cancels the action. Iif you tap the jump button it jumps a little and the more you hold the jump button the more it jumps.

Thanks in advance, here is the code:

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [Header("References")]
    [SerializeField] PlayerInput _playerInput;
    [SerializeField] CharacterController _characterController;
    [SerializeField] Transform _camera;
    [SerializeField] AudioData_SO _footstepClip;
    [SerializeField] Transform _headTransform;

    [Header("Movement Speeds")]
    [SerializeField] float _walkSpeed;
    [SerializeField] float _runSpeed;
    [SerializeField] float _crouchSpeed;
    [SerializeField] float _gravityForce = -9.81f;
    Vector3 _movementDirection;
    float _footstepTimer;
    float _speed;

    [Header("Ground Detection")]
    [SerializeField] bool _isGrounded;

    [Header("Jumping")]
    [SerializeField] float _jumpMaxTime;
    [SerializeField] float _jumpForce;
    [SerializeField] float _jumpStartingForce;
    float _jumpTimer;
    bool _holdingJumpButton;
    bool _isJumping;

    [Header("Air Movement")]
    [SerializeField] float _airRotationSpeed;
    [SerializeField] float _baseAirSpeed;

    [Header("Crouching")]
    [SerializeField] float _standHeight;
    [SerializeField] float _crouchHeight;
    [SerializeField] Vector3 _headStandOffset;
    [SerializeField] Vector3 _headCrouchOffset;
    Vector3 _charCenter = new();
    bool _isCrouching;

    Vector3 _velocity = new();
    Vector3 _flatVelocity = new();
    float _angle;

    void Start()
    {
        _playerInput.actions["Jump"].started += ctx => StartJump();
        _playerInput.actions["Jump"].performed += ctx => StopJump();
        _playerInput.actions["Jump"].canceled += ctx => StopJump();
        _playerInput.actions["Crouch"].started += ctx => StartCrouch();
        _playerInput.actions["Crouch"].canceled += ctx => StopCrouch();
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
        _charCenter = _characterController.center;
        _speed = _walkSpeed;
    }

    void Update()
    {
        _isGrounded = _characterController.isGrounded;
        transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, _camera.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);
        ParseInputs(); // Gets the player's input

        if (_isGrounded)
        {
            if (_velocity.y < -5f) 
                _velocity.y = -5f; // Stops gravity from acumulating when player is on the ground
            GroundedMovement();
        }
        else
            AirMovement();

        VerifyJump(); // Check if the player can and is trying to jump

        if (!_isJumping && !_isGrounded)
            _velocity.y += _gravityForce * Time.deltaTime; // Apply gravity force

        //if (Physics.Raycast(_headTransform.position, Vector3.up, 0.25f)) // Check for playing hitting its head on the ceiling
        //{
        //    if (_isJumping)
        //    {
        //        _isJumping = false;
        //        _velocity.y = 0;
        //    }

        //    _velocity.y = 0;
        //}

        _characterController.Move(_velocity * Time.deltaTime);
    
        PlayFootstepsAudio();
    }

    void GroundedMovement()
    {
        if (!Mathf.Approximately(_playerInput.actions["Run"].ReadValue<float>(), 0))
        {
            if (_isCrouching)
                StopCrouch();

            _speed = _runSpeed;
        }
        else if (_isCrouching)
            _speed = _crouchSpeed;
        else
            _speed = _walkSpeed;

        _velocity.x = _speed * _movementDirection.x;
        _velocity.z = _speed * _movementDirection.z;
    }

    void AirMovement()
    {
        _flatVelocity.x = _velocity.x;
        _flatVelocity.z = _velocity.z;
        _angle = Vector3.Angle(_flatVelocity, _movementDirection);

        if (Mathf.Approximately(_flatVelocity.magnitude, 0))
            _speed = _baseAirSpeed;

        // Check if the angle between _movementDirection and _velocity is lesser or equal to 135 and greater than 0
        //// In this case make the _velocity rotate towards the _movementDirection

        if (_angle <= 135)
        {
            _flatVelocity.Normalize();
            _flatVelocity = Vector3.Slerp(_flatVelocity, _movementDirection, _airRotationSpeed * Time.deltaTime);
            _velocity.x = _flatVelocity.x * _speed;
            _velocity.z = _flatVelocity.z * _speed;
        }

        // When the angle between _movementDirection and _velocity is greater than 135 make the _velocity reduce overtime
        if (_angle > 135)
        {
            _velocity.x -= _velocity.x;
            _velocity.z -= _velocity.z;
        }
    }

    void StartCrouch()
    {
        if (CanvasManager_InGame.Instance.IsGamePaused || !_isGrounded) return;

        _isCrouching = true;

        _characterController.height = _crouchHeight;
        _charCenter.y = _crouchHeight / 2;
        _characterController.center = _charCenter;

        _headTransform.localPosition = _headCrouchOffset;
    }

    void StopCrouch()
    {
        _isCrouching = false;

        _characterController.height = _standHeight;
        _charCenter.y = _standHeight / 2;
        _characterController.center = _charCenter;

        _headTransform.localPosition = _headStandOffset;
    }

    void StartJump()
    {
        if (CanvasManager_InGame.Instance.IsGamePaused) return;
        _holdingJumpButton = true;
    }

    private void StopJump()
    {
        if (CanvasManager_InGame.Instance.IsGamePaused) return;
        _holdingJumpButton = false;
        _isJumping = false;
    }

    void VerifyJump()
    {
        if (!_holdingJumpButton) return;

        if (_isGrounded && !_isJumping) // Starts jump
        {
            if (_isCrouching)
                StopCrouch();
            _velocity.y = _jumpStartingForce;
            _isJumping = true;
            _jumpTimer = 0;
        }

        if (_isJumping)
        {
            _jumpTimer += Time.deltaTime;
            if (_jumpTimer >= _jumpMaxTime)
                StopJump();

            _velocity.y += _jumpForce;
        }
    }

    void ParseInputs()
    {
        _movementDirection = Vector3.zero;
        _movementDirection += transform.right * _playerInput.actions["Move"].ReadValue<Vector2>().x;
        _movementDirection += transform.forward * _playerInput.actions["Move"].ReadValue<Vector2>().y;
    }

    void PlayFootstepsAudio()
    {
        if (_footstepTimer > 0.25f && _playerInput.actions["Run"].ReadValue<float>() != 0)
            _footstepTimer = 0.25f;

        if (_footstepTimer <= 0 && _playerInput.actions["Move"].ReadValue<Vector2>() != Vector2.zero && _isGrounded)
        {
            AudioManager.Instance.PlayClipOneShot(_footstepClip);

            if (_playerInput.actions["Run"].ReadValue<float>() != 0)
                _footstepTimer = 0.25f;
            else
                _footstepTimer = 0.5f;
        }
        else
            _footstepTimer -= Time.deltaTime;
    }
}

And the Jump action setup i’m using just in case: