Merge join turns to hash match when adding a 2nd join
I think this stack exchange link gives a good rundown of why it is doing what it is doing, and I believe it has most to do with the size of the results sets and how they are indexed/sorted in your case.    Order and Order Details, from this database are 830 rows  and 2155 rows respectively.   These are similar results sets where one has 2 rows (roughly) for every one row in the other table.   Order Details is clustered on  OrderID, ProductID - meaning that the table is also sorted that way.   Orders is obviously clustered on OrderID as well, meaning that it is also sorted on orderid.   I believe this makes it easy to merge these two data sets that are already sorted in this way together.

Then you throw in Products.    If you run the query

SELECT * FROM dbo.[Order Details] AS od
ORDER BY OrderID, od.ProductID


This is basically showing you what the logical order of the Order Details table is.   And if you look at it from a products perspective it looks basically random.   So now you are throwing in a join to a table that is only 77 rows and where the sorting does not really match up.

I believe that is why you see the Merge Join for the first and the Hash for the second.  

Read that link above as it gives a nice description of these things and how they work.    Another good one is at this other SE article.

Lots of information in those two and at many other places (including your book).