Moving an object forward relative to Vive Controller

I’m trying to implement a pool queue that I’d like to move along its forward (blue) axis according to movement from the Vive Controller. When the right controller is clicked, movement should be locked to the forward axis. Rotation is locked as well.

I’m using this code in a script on the GameObject that has the queue model as a child:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class QueueControllerNew : MonoBehaviour
{
	public GameObject c1, c2, pivot;
	public SteamVR_TrackedObject leftCtrl, rightCtrl;

	Vector3 lastPosition; // stores the left controller's last position

	void Awake ()
	{
		lastPosition = c1.transform.position;
	}

   	void Update ()
	{
		lastPosition = transform.TransformDirection (c1.transform.position);
	}

	void FixedUpdate ()
	{
   		var deviceLeft = SteamVR_Controller.Input ((int)leftCtrl.index);
		var deviceRight = SteamVR_Controller.Input ((int)rightCtrl.index);

		if (deviceRight.GetHairTrigger ()) {  // when the trigger is pressed, lock movement to forward vector
			transform.position += (transform.forward * (transform.TransformDirection (c1.transform.position) - lastPosition).z);
			
		} else { // lock position to left controller's position and look at right controller
			transform.position = c1.transform.position;
			transform.LookAt (c2.transform.position);
		}

	}

}

The code works well as long as both the queue and the left controller are parallel to the world’s z-axis. As soon as the queue rotation changes, the directions get all messed up. I (think I) know that this is because the forward vector changes and I’m still using the z value of the left controller but I just don’t get how this can be done dynamically.

Any pointers you can give me?

After talking to a technical mathematician he proposed using orthogonal projection which I used in the working code you see below.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class QueueControllerNew : MonoBehaviour
{
	public GameObject c1, c2, pivot;
	public SteamVR_TrackedObject leftCtrl, rightCtrl;

	Vector3 v0, v;

	void Awake ()
	{
		v0 = c1.transform.position; // last known position of left controller
	}

	void FixedUpdate ()
	{
		var deviceLeft = SteamVR_Controller.Input ((int)leftCtrl.index);
		var deviceRight = SteamVR_Controller.Input ((int)rightCtrl.index);
		if (deviceLeft.GetTouchDown (SteamVR_Controller.ButtonMask.Grip)) {
			HandleGripped ();
		}

		if (deviceRight.GetHairTrigger ()) {
			
			v = c1.transform.position - v0; // offset of left controller relative to last frame

			transform.position += (Vector3.Dot (transform.forward, v) / Vector3.Dot (transform.forward, transform.forward)) * transform.forward; // orthogonal projection along the queue's forward vector

		} else {
			transform.position = c1.transform.position;
			transform.LookAt (c2.transform.position);

		}
		v0 = c1.transform.position; // save new left controller position
	}

}