Two optimizations to avoid ~2min wasted per file on re-runs:
1. pipeline.py: Check which visualizations need regeneration before
computing SharedDEM. If all WebP outputs exist, skip SharedDEM
entirely. If only IGN overlays need updating, also skip SharedDEM.
2. visualizations.py: Make SharedDEM attributes lazy (filled, gradient,
lrm_15) so only the data actually needed is computed. For example,
if only hillshade is regenerated, LRM at 15m is never calculated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>