>Both tables and indexes use the same b+-tree implementation based on Lehman and Yao (prev/next links on internal nodes).
Tables in Postgres are not btree's they are unordered heaps. The row id in the b-tree index points to a page number + item index in the heap.
A true clustered index would simply expose the index itself as a table without secondary heap storage, reducing I/O and storage space. Row visibility seems to complicate this in PG as index only scans may require checking the heap for visibility.
Both tables and indexes use the same b+-tree implementation based on Lehman and Yao (prev/next links on internal nodes).
> Each page can hold some number of fixed size tuples
Variable size.
> Variable length strings are kept in a separate file
Only if the row exceeds the page size, otherwise everything is stuffed into the data leaf node.
> I'm not quite sure how the allocation scheme or data structure works there
Values are broken up into DataSize/PageSize "virtual rows" and stitched back together, but everything is still in the same slotted page structure.