Swaps the stepped-path mark for the "C1 v2" design: an 8x8 grid of graded
day-cells tracing the same climb (blue Low -> green Normal -> a hot loop -> a
stepped ascent to the near-record red cell). It keeps the exact geometry of the
old mark — same 512 viewBox, same 32/448/rx96 rounded badge, same band palette —
so it is a drop-in that needs no alignment changes.
Everywhere the mark appears:
- The inline header SVG in all six lockups (the five standalone frontend pages
and backend/templates/base.html.j2), kept at width/height 28 with aria-hidden.
Because the box and viewBox are unchanged, the .logo/.brand alignment CSS
(the -2px cap-height nudge, the 28->22px compact size, the 10px gap) is
untouched and the mark stays centred on the "Thermograph" wordmark.
- favicon.svg, regenerated from the new art.
- Every raster: favicon-16/32/48, apple-touch-icon (180), logo-192, logo (512),
and the two maskable icons. The maskable pair keeps the established recipe —
the badge scaled into the central safe zone on a full-bleed opaque square — so
an OS shape mask never clips the art.
Bumps every icon reference to ?v=3 (previously a mix of ?v=2 and unversioned) so
browsers and installed PWAs refetch the new icons.
Claude-Session: https://claude.ai/code/session_013dRZmX9D3JEntfMKWMTWZ8
The mark is a quantized climb through the temperature-band tokens
(cold -> cool -> normal -> warm -> hot -> very-hot) to a rec-hot
terminal at a dashed record line, on the dark rounded tile.
- favicon.svg (canonical) + favicon-16/32/48.png fallbacks; the 16px
raster drops the whisper strata and record dash so the climb survives
- apple-touch-icon.png 180 rendered edge-to-edge (iOS supplies rounding)
- maskable 192/512 scale the artwork 0.78 about center so every element
clears the 40%-radius circular safe zone; any-purpose 192/512 and the
512 OG logo.png regenerated; reused filenames cache-busted with ?v=2
- header lockup: inline glyph referencing var(--cold) etc so a palette
change propagates, beside a lowercase 650-weight wordmark
- PNGs are palette-quantized with the band/chrome hexes pinned exact;
full asset set is ~20 KB
Claude-Session: https://claude.ai/code/session_01KdTZCjpLeD26ZbXe6ApjpR
Make the app installable and deliver existing alert notifications as OS
push, alongside the in-app bell.
Backend:
- PushSubscription model (per-device endpoint + keys, owned by a user) and
register/unregister/test endpoints under /api/v2/push, cookie-auth scoped
to the user like the subscription routes.
- push.py: VAPID key management (env -> data/vapid.json -> generated) and a
pywebpush send helper that reports gone endpoints for pruning. No DB coupling.
- notify.py: after creating an in-app Notification, dispatch Web Push to the
user's devices (guarded — a push failure never affects the in-app write;
endpoints reported gone are pruned).
- Serve the .webmanifest with the correct media type.
Frontend:
- manifest.webmanifest + 192/maskable icons; <link rel="manifest"> on all pages.
- sw.js: push + notificationclick handlers (push-only; no fetch caching, so it
doesn't fight the existing IndexedDB cache). Registered globally in nav.js in
secure contexts.
- push-client.js + a "Notifications on this device" toggle and test-send on the
/alerts page, subscribing through the existing cookie-aware apiFetch.
Push and service workers require a secure context, so this is active over HTTPS
(or http://localhost) and cleanly no-ops on a plain-HTTP LAN origin.