Replace the per-row model_dump(mode='python') walk in Page.to_dataframe
and Page.to_polars with a column-oriented dict[field, list[value]] built
once via getattr. For a 1000-row trades_history page this avoids 1000
nested-dict allocations plus per-field Python-level conversion, and
lets pandas/polars infer dtypes from homogeneous columns instead of
re-inferring from records.
Nested BaseModel cells are still dumped per-column (mode='python') so
that polars can infer Struct from the resulting dicts — a plain
BaseModel column raises 'Decimal without precision/scale set is not a
valid Polars datatype'. The #225 / #190 Decimal contract is preserved
(DollarDecimal lands as Decimal, list[Decimal] stays list[Decimal],
nested Decimal survives Struct round-trip).
Empty pages short-circuit to pd.DataFrame() / pl.DataFrame() to avoid
indexing items[0] on an empty list.
Tests: add 100-row column-oriented regression coverage for both
backends + empty-page sentinels in tests/test_page_dataframe.py.
Existing #101 nested-shape and #190 DollarDecimal pins still pass
unchanged.
Closes #264
Closes #264
Part of #273 (post-v2.4 audit), Wave 2.