Are you sure you need to reproject?  NAVD88 should be in Survey (US) Feet, last I checked.  We use the same here, as well.
I also see that you used to just use the attribute table, rather than the back-end Z-coordinates.  First dumb question: Are you actually using the back-end coordinates, now?
One quick way to check would be with an arcpy cursor:
Change lines 1 & 5 with the path to your FC and the name of your attribute table elevation field, respectively.
 
fc = 'path_to_your_feature_class'
max_features = 50 # This is just to run on a subset, rather than everything
count = 0         # Subset testing
with arcpy.da.SearchCursor(fc, ['OID@', 'SHAPE@', 'ElevationField']) as cursor:
  for oid, geo, elevAttr in cursor:
    count += 1    # Subset testing
    if count >= max_features: # Subset testing
      break       # Subset testing
    arcpy.AddMessage(f'{oid}\n  ({geo.firstPoint.X}, {geo.firstPoint.Y}, {geo.firstPoint.Z})\n  ({elevAttr})\n')
 
 
You should get something like the following:

(I ran this on a test dataset that doesn't have any elevation values populated, so the 0.0 is expected, in my case).
The first row is the actual X, Y, Z of a point in your feature class.  If it's a line or polygon, it'll be the first vertex.
The second row is the Z value in your elevation attribute field.
If that last value on row 1 doesn't match the number that's by itself, then that's your problem.  ArcGIS can only project things based on those hidden back-end coordinates.  Anything in the attribute table is just for show.
					
				
			
			
				
	------------------------------
M Reed
"The pessimist may be right oftener than the optimist, but the optimist has more fun, and neither can stop the march of events anyhow." — Lazarus Long, in Time Enough for Love, by Robert A. Heinlein