{{/* Ported from templates/base.html.j2 (Jinja, trim_blocks + lstrip_blocks + keep_trailing_newline=False). The Jinja layout used {% extends %}/{% block %}; in a single html/template parse set a per-page {{define "title"}} would collide across the 10 pages, so the layout is instead split into sequential chunks that every page template stitches together in order: base_head_start doctype .. the manifest . title/description/ canonical/og:* are data-driven (.PageTitle, .PageDescription, .CanonicalPath) — the og:title / og:url duplication Jinja did via self.title() falls out for free. [page head_extra] inline in the page file (home: leaflet css) base_head_end the style.css [page jsonld] inline in the page file (city/records/glossary_term/home) base_body_start .. header + nav ..
[page content] base_body_end
.. footer [page body_scripts] base_scripts_default, or the page's own (home) base_tail digest/ios-install scripts, Whitespace mirrors the Jinja env's exact output byte-for-byte (golden-diff contract): control tags on their own line vanished entirely under trim_blocks/lstrip_blocks, so here the equivalent actions are glued to the start of the following content line; keep_trailing_newline=False means the document ends at with no final newline (see base_tail). HTML comments that must SURVIVE into the output go through the `comment` FuncMap helper, because html/template strips literal comments. Data contract (all pages): .Base .AssetBase .AssetBaseURL .BaseURL .UnitDefault .Section .BrandTag ("h1"; home passes "p") .MainClass ("content"; home passes "") .PageTitle .PageDescription .CanonicalPath .Fmt (unit-bound formatter: Temp/TempBare/TempClass) and, on pages that have one, .Breadcrumb []contentapi.Crumb. */}} {{define "base_head_start" -}} {{head_verify}} {{.PageTitle}} {{comment `iOS/Android home-screen install: run standalone (no browser chrome) when added to the Home Screen. On iOS 16.4+ this is what unlocks Web Push.`}} {{end}} {{define "base_head_end" -}} {{end}} {{/* The brand lockup (logo svg + wordmark) shared by both brand-tag variants below. */}} {{define "brand_link"}}Thermograph{{end}} {{define "base_body_start" -}}
{{/* The brand is the page's h1 everywhere EXCEPT the homepage, where the hero headline owns the sole h1 and the brand degrades to a

. The .brand h1, .brand .site-name selector pair in style.css keeps the lockup looking identical either way. (The Jinja original wrote <{{ brand_tag|default('h1') }} …>; html/template forbids actions in tag names, hence two literal branches around one shared lockup.) */}} {{if eq .BrandTag "p"}}

{{template "brand_link" .}}

{{else}}

{{template "brand_link" .}}

{{end}}

How unusual is the weather? Graded against ~45 years of local climate history.

{{end}} {{define "base_body_end" -}}
{{/* The compact digest signup is the site-wide footer pattern, not a homepage-only surface: every page is a possible entry point. Hidden for now; restore by uncommenting the form block below (kept verbatim from the Jinja original — {{ asset_base }} becomes {{.AssetBase}} when it comes back):

No spam, no sharing your address, unsubscribe anytime.

*/}}

Free. No ads. No tracking. No account needed. Built by one person in the open.

Thermograph grades weather by its percentile against ~45 years of local climate history. Data: ERA5 via Open-Meteo · NASA POWER · MET Norway.

Made by emigriffith.dev @

{{end}} {{define "base_scripts_default" -}} {{comment `Header parity with the interactive pages: the °F/°C toggle, account + bell, and the client-side temperature converter. All self-contained modules.`}} {{end}} {{define "base_tail" -}} {{end}} {{/* Shared breadcrumb nav (each Jinja page repeated this line verbatim; the output is identical, so it is factored here). The separator is emitted BEFORE every non-first crumb — same byte stream as Jinja's `{% if not loop.last %}` after-each-but-last. Crumb.Href is *string (terminal crumb: null). */}} {{define "breadcrumb" -}} {{end}}