How to read an encoder and control a stepper motor without delay()

Some questions...
If the stepper and encoder are hooked to the same thing, do you even need the encoder? All it's going to tell you is how far the motor turned, but since it's a stepper motor you should know that anyway just by counting the steps.

Also, I see it's a quadrature encoder. Those are great when you don't know which way the thingy (technical term) is rotating. Is that the case here, or do you already know the direction? If so, then you can vastly simplify the encoder handling code (just count interrupts).

Other points
ISRs should be as short and simple as possible. Don't do delays, don't do library calls that take a long time. keep the logic short and simple. Ideally, you should just set flags or change counters and do the rest in the main loop.

In general, encoders don't need to be debounced. Every transition means something. There is the case of "jitter" but you can fix that by ignoring "double" interrupts (if you get A, A, A, A with no B's then this is probably jitter).

On the other hand, buttons DO need to be debounced, or they are unreliable as input. Adding debouncing code will complicate your sketch, but it's necessary. Look in the playground for stuff you can copy or use directly.

bugs/nits
The variable encoderPos is declared as an unsigned int. It is entirely possible that it could go below 0 depending on which way the encoder rotates. Also, if you get a lot of movement, it could overflow. Try using volatile long as the type instead. Change lastReportedPos to match.

You don't need an enum for the input pins. #define's work just fine for pin numbers in most cases.

Don't do clearDisplay in the main loop. It's not necessary and is probably not what you want. You could probably move some of the LCD writing to the setup function and just display the number in the main loop.

HTH,