Sharing a Thermograph URL (Discord, Slack, iMessage…) now unfurls into a
card with the site name, page title, description, accent color, and logo.
- All five pages get description/theme-color/og:*/twitter:card meta and a
favicon. og:url/og:image need absolute URLs and crawlers don't run JS, so
pages carry an __ORIGIN__ placeholder the server fills in per request from
X-Forwarded-Proto (Caddy) / scheme + the Host header + base path — correct
on both the LAN dev server and the prod domain without hardcoding either.
- New logo assets: the header's ▚ mark as an app icon (accent quadrants on
the dark surface) — logo.png (512x512, the og:image) and logo.svg (favicon).
- Page routes render the substitution with a weak ETag + 304 revalidation
(replacing plain FileResponse) and now answer HEAD, which preview crawlers
probe with (previously 404).
Compare page (frontend/compare.{html,js} + /thermograph/compare route):
line up several places over a date range and rank which best matches a
comfort temperature. Per location it pulls the same daily record the
Calendar uses and, per day, takes a chosen temperature (daytime high /
daily mean / overnight low / feels-like) against the comfort target. A
day "hits comfort" when it lands within an adjustable band; otherwise it
counts as colder or warmer and the average miss is tracked. Results are
ranked by comfort-day share (tie-broken by the smaller typical miss),
with a diverging below/comfort/above bar and per-bucket stats. Comfort,
band and judged temperature re-rank instantly client-side; only the
location set or date range trigger a data load (shared calendar cache).
Feels calendar filter: drop the comfort-temperature slider and the
client-side felt-high/felt-low re-pick. The Feels metric now colors by
the server's combined feels-like value like the other metrics, so its
tab matches the rest of the metric selector.