Remove em-dashes from site copy and tighten the prose (#206)
Replace em-dashes in user-facing copy across the server-rendered pages, static frontend views, and the strings the app injects at runtime, using colons, commas, parentheses or full stops as the context wants. Data placeholder glyphs (a lone "—" for a missing reading) are left alone, since a hyphen there reads as a minus sign in temperature columns. Also tighten the high-visibility surfaces (home hero and meta, about, privacy, city and records ledes, glossary blurbs) toward a plainer, more direct voice while keeping every factual claim intact. Claude-Session: https://claude.ai/code/session_01XXxmNFy9cZ6Gh8Y9thZn62
This commit is contained in:
parent
6726544b56
commit
28b10a0783
14 changed files with 52 additions and 52 deletions
|
|
@ -13,7 +13,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "In August 2005, Hurricane Katrina overwhelmed the city's levees and flooded roughly 80% of New Orleans, one of the deadliest and costliest disasters in U.S. history.",
|
||||
"url": "https://en.wikipedia.org/wiki/Effects_of_Hurricane_Katrina_in_New_Orleans"},
|
||||
"houston-texas-us": {
|
||||
"text": "In August 2017, Hurricane Harvey stalled over the region and dropped more than 50 inches of rain — a record for a U.S. tropical cyclone — causing catastrophic flooding across Houston.",
|
||||
"text": "In August 2017, Hurricane Harvey stalled over the region and dropped more than 50 inches of rain, a record for a U.S. tropical cyclone, causing catastrophic flooding across Houston.",
|
||||
"url": "https://en.wikipedia.org/wiki/Hurricane_Harvey"},
|
||||
"chicago-illinois-us": {
|
||||
"text": "A brutal heat wave in July 1995 pushed the heat index past 120°F and caused an estimated 700 heat-related deaths in Chicago, reshaping how the city prepares for extreme heat.",
|
||||
|
|
@ -28,7 +28,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "The Blizzard of 1978 paralyzed Boston for a week, dropping about 27 inches of snow, stranding thousands of motorists, and flooding coastal neighborhoods.",
|
||||
"url": "https://en.wikipedia.org/wiki/Northeastern_United_States_blizzard_of_1978"},
|
||||
"seattle-washington-us": {
|
||||
"text": "During the June 2021 Western North America heat wave, Seattle hit an all-time record 108°F — a temperature the normally mild city had never before approached.",
|
||||
"text": "During the June 2021 Western North America heat wave, Seattle hit an all-time record 108°F, a temperature the normally mild city had never before approached.",
|
||||
"url": "https://en.wikipedia.org/wiki/2021_Western_North_America_heat_wave"},
|
||||
"portland-oregon-us": {
|
||||
"text": "In the June 2021 heat dome, Portland reached an all-time record 116°F across three consecutive record-shattering days.",
|
||||
|
|
@ -40,7 +40,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "Deep in Tornado Alley, the Oklahoma City area was struck by the May 3, 1999 tornado, which produced the highest wind speed ever measured on Earth, around 302 mph.",
|
||||
"url": "https://en.wikipedia.org/wiki/1999_Bridge_Creek%E2%80%93Moore_tornado"},
|
||||
"los-angeles-california-us": {
|
||||
"text": "In January 2025, wind-driven wildfires — chiefly the Palisades and Eaton fires — swept through Los Angeles, destroying thousands of structures in one of the most destructive fire disasters in California's history.",
|
||||
"text": "In January 2025, wind-driven wildfires, chiefly the Palisades and Eaton fires, swept through Los Angeles, destroying thousands of structures in one of the most destructive fire disasters in California's history.",
|
||||
"url": "https://en.wikipedia.org/wiki/January_2025_Southern_California_wildfires"},
|
||||
|
||||
# --- Canada ---
|
||||
|
|
@ -65,7 +65,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "In the summer of 2010, a record heat wave and surrounding peat and forest fires smothered Moscow in smog for weeks, with temperatures near 38°C and thousands of excess deaths.",
|
||||
"url": "https://en.wikipedia.org/wiki/2010_Russian_wildfires"},
|
||||
"madrid-es": {
|
||||
"text": "In January 2021, Storm Filomena buried Madrid under its heaviest snowfall in decades — around 50 cm — paralyzing the city for days.",
|
||||
"text": "In January 2021, Storm Filomena buried Madrid under its heaviest snowfall in decades, around 50 cm, paralyzing the city for days.",
|
||||
"url": "https://en.wikipedia.org/wiki/Storm_Filomena"},
|
||||
"athens-attica-gr": {
|
||||
"text": "In July 2018, wind-driven wildfires swept through Attica near Athens during extreme heat, killing more than 100 people in Greece's deadliest fire disaster.",
|
||||
|
|
@ -76,7 +76,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "During the 2019–20 'Black Summer' bushfires, hazardous smoke repeatedly blanketed Sydney, pushing its air quality to some of the worst of any major city.",
|
||||
"url": "https://en.wikipedia.org/wiki/2019%E2%80%9320_Australian_bushfire_season"},
|
||||
"melbourne-victoria-au": {
|
||||
"text": "On 'Black Saturday' in February 2009, extreme heat and wind drove bushfires across Victoria, around Melbourne, that killed 173 people — Australia's deadliest bushfires.",
|
||||
"text": "On 'Black Saturday' in February 2009, extreme heat and wind drove bushfires across Victoria, around Melbourne, that killed 173 people in Australia's deadliest bushfires.",
|
||||
"url": "https://en.wikipedia.org/wiki/Black_Saturday_bushfires"},
|
||||
"brisbane-queensland-au": {
|
||||
"text": "The 2010–11 Queensland floods peaked in January 2011 when the Brisbane River burst its banks, flooding thousands of homes and businesses across the city.",
|
||||
|
|
@ -90,7 +90,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "The December 2015 South Indian floods submerged much of Chennai after its heaviest rains in over a century, displacing hundreds of thousands.",
|
||||
"url": "https://en.wikipedia.org/wiki/2015_South_India_floods"},
|
||||
"kolkata-west-bengal-in": {
|
||||
"text": "In May 2020, Cyclone Amphan — the most powerful storm recorded in the Bay of Bengal — struck Kolkata directly, uprooting trees and cutting power across the city.",
|
||||
"text": "In May 2020, Cyclone Amphan, the most powerful storm recorded in the Bay of Bengal, struck Kolkata directly, uprooting trees and cutting power across the city.",
|
||||
"url": "https://en.wikipedia.org/wiki/Cyclone_Amphan"},
|
||||
"karachi-sindh-pk": {
|
||||
"text": "A severe heat wave in June 2015 killed an estimated 1,200 people in Karachi as temperatures reached about 45°C during Ramadan.",
|
||||
|
|
@ -114,7 +114,7 @@ EVENTS: dict[str, dict] = {
|
|||
"text": "Super Typhoon Mangkhut battered Hong Kong in September 2018 with fierce winds and a storm surge, flooding low-lying districts and swaying skyscrapers.",
|
||||
"url": "https://en.wikipedia.org/wiki/Typhoon_Mangkhut"},
|
||||
"tokyo-jp": {
|
||||
"text": "In October 2019, Typhoon Hagibis — one of the most powerful to strike Japan in decades — brought record rainfall and widespread flooding to the Tokyo region.",
|
||||
"text": "In October 2019, Typhoon Hagibis, one of the most powerful to strike Japan in decades, brought record rainfall and widespread flooding to the Tokyo region.",
|
||||
"url": "https://en.wikipedia.org/wiki/Typhoon_Hagibis"},
|
||||
"seoul-kr": {
|
||||
"text": "In August 2022, record-breaking rainfall flooded Seoul, submerging roads and low-lying semi-basement homes and killing several people across the capital region.",
|
||||
|
|
@ -122,7 +122,7 @@ EVENTS: dict[str, dict] = {
|
|||
|
||||
# --- Middle East ---
|
||||
"dubai-ae": {
|
||||
"text": "In April 2024, Dubai was deluged by about two years' worth of rain in a single day — its heaviest on record — flooding highways and bringing its international airport to a standstill.",
|
||||
"text": "In April 2024, Dubai was deluged by about two years' worth of rain in a single day, its heaviest on record, flooding highways and bringing its international airport to a standstill.",
|
||||
"url": "https://en.wikipedia.org/wiki/2024_United_Arab_Emirates_floods"},
|
||||
"jeddah-mecca-region-sa": {
|
||||
"text": "In November 2009, sudden flash floods swept through Jeddah after record rainfall, killing more than 100 people in one of the city's worst modern disasters.",
|
||||
|
|
@ -138,7 +138,7 @@ EVENTS: dict[str, dict] = {
|
|||
|
||||
# --- Africa ---
|
||||
"cape-town-western-cape-za": {
|
||||
"text": "From 2015 to 2018 a severe drought pushed Cape Town toward 'Day Zero' — the day municipal taps would be shut off — narrowly averted through drastic water conservation.",
|
||||
"text": "From 2015 to 2018 a severe drought pushed Cape Town toward 'Day Zero', the day municipal taps would be shut off, narrowly averted through drastic water conservation.",
|
||||
"url": "https://en.wikipedia.org/wiki/Cape_Town_water_crisis"},
|
||||
"durban-kwazulu-natal-za": {
|
||||
"text": "In April 2022, extreme rainfall triggered catastrophic floods and landslides around Durban, killing more than 400 people in one of South Africa's deadliest storms.",
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ class WeatherUnavailable(RuntimeError):
|
|||
def limit_message(daily: bool) -> str:
|
||||
"""The user-facing rate-limit copy, in one place."""
|
||||
if daily:
|
||||
return ("Open-Meteo's daily request limit is exhausted — new locations will work again "
|
||||
return ("Open-Meteo's daily request limit is exhausted, so new locations will work again "
|
||||
"tomorrow. Places you've already viewed still work.")
|
||||
return "The weather service is rate-limited right now — please try again in a minute."
|
||||
return "The weather service is rate-limited right now. Please try again in a minute."
|
||||
|
||||
|
||||
def is_rate_limit(e) -> bool:
|
||||
|
|
|
|||
24
content.py
24
content.py
|
|
@ -796,7 +796,7 @@ def hub_page(request: Request) -> Response:
|
|||
"n_countries": len(groups),
|
||||
"canonical_path": "/climate",
|
||||
"breadcrumb": [("Home", f"{BASE}/"), ("Climate", None)],
|
||||
"page_title": "City climate pages — averages, records and how today compares",
|
||||
"page_title": "City climate pages: averages, records and how today compares",
|
||||
"page_description": ("Browse climate pages for hundreds of cities worldwide: average temperatures by "
|
||||
"month, all-time records, and how today's weather compares to local history."),
|
||||
}
|
||||
|
|
@ -810,19 +810,19 @@ GLOSSARY: dict[str, dict] = {
|
|||
"short": "The typical value of a weather metric for a place and time of year, averaged over decades.",
|
||||
"body": "A <b>climate normal</b> is the long-term average of a weather variable (say, the daily high) "
|
||||
"for a specific place and time of year. Thermograph builds each day's normal from every "
|
||||
"historical day within ±7 days of that day-of-year, across ~45 years — so a day is judged "
|
||||
"historical day within ±7 days of that day-of-year, across ~45 years, so a day is judged "
|
||||
"against its own season, not a single annual average.",
|
||||
},
|
||||
"percentile": {
|
||||
"term": "Percentile",
|
||||
"short": "Where a value ranks within a distribution — the 90th percentile is warmer than 90% of days.",
|
||||
"short": "Where a value ranks within a distribution: the 90th percentile is warmer than 90% of days.",
|
||||
"body": "A <b>percentile</b> says where a value falls within a range of past values. If today's high is at "
|
||||
"the 97th percentile, only about 3% of comparable days in this location's history were warmer. "
|
||||
"Thermograph grades every day by its percentile against the local ±7-day seasonal distribution.",
|
||||
},
|
||||
"temperature-anomaly": {
|
||||
"term": "Temperature anomaly",
|
||||
"short": "How far a temperature departs from normal — the difference from the long-term average.",
|
||||
"short": "How far a temperature departs from normal: the difference from the long-term average.",
|
||||
"body": "A <b>temperature anomaly</b> is how much warmer or colder it is than the local normal for the "
|
||||
"time of year. Thermograph expresses the same idea as a percentile and a grade (from “Below "
|
||||
"Normal” to “Near Record”), so an anomaly is easy to read at a glance for any location.",
|
||||
|
|
@ -852,15 +852,15 @@ GLOSSARY: dict[str, dict] = {
|
|||
"humidity": {
|
||||
"term": "Absolute humidity",
|
||||
"short": "The actual mass of water vapor in the air, in grams per cubic meter.",
|
||||
"body": "Thermograph reports <b>absolute humidity</b> (g/m³) — the real amount of water vapor in the "
|
||||
"air — rather than relative humidity, which shifts with temperature. Graded against local history, "
|
||||
"body": "Thermograph reports <b>absolute humidity</b> (g/m³), the real amount of water vapor in the "
|
||||
"air, rather than relative humidity, which shifts with temperature. Graded against local history, "
|
||||
"it shows genuinely muggy or unusually dry days.",
|
||||
},
|
||||
"reanalysis": {
|
||||
"term": "Reanalysis (ERA5)",
|
||||
"short": "A gridded, physically-consistent record of past weather for anywhere on Earth.",
|
||||
"body": "A <b>reanalysis</b> blends historical observations with a weather model to produce a consistent "
|
||||
"record of past conditions everywhere — even where no station exists. Thermograph's ~45-year history "
|
||||
"record of past conditions everywhere, even where no station exists. Thermograph's ~45-year history "
|
||||
"comes from ECMWF's <b>ERA5</b> reanalysis (via Open-Meteo), which is why it works for any point on Earth.",
|
||||
},
|
||||
}
|
||||
|
|
@ -875,7 +875,7 @@ def glossary_index(request: Request) -> Response:
|
|||
"terms": [{"slug": s, **e} for s, e in GLOSSARY.items()],
|
||||
"canonical_path": "/glossary",
|
||||
"breadcrumb": [("Home", f"{BASE}/"), ("Glossary", None)],
|
||||
"page_title": "Weather & climate glossary — heat index, feels-like, percentile, and more",
|
||||
"page_title": "Weather & climate glossary: heat index, feels-like, percentile, and more",
|
||||
"page_description": ("Plain-language definitions of weather and climate terms: climate normal, percentile, "
|
||||
"temperature anomaly, feels-like, heat index, wind chill, humidity, and reanalysis."),
|
||||
}
|
||||
|
|
@ -890,7 +890,7 @@ def glossary_term(request: Request, term: str) -> Response:
|
|||
"term": entry["term"], "body": _glossary_body(entry),
|
||||
"canonical_path": f"/glossary/{term}",
|
||||
"breadcrumb": [("Home", f"{BASE}/"), ("Glossary", f"{BASE}/glossary"), (entry["term"], None)],
|
||||
"page_title": f"{entry['term']} — what it means | Thermograph",
|
||||
"page_title": f"{entry['term']}: what it means | Thermograph",
|
||||
"page_description": entry["short"],
|
||||
"others": [{"slug": s, "term": e["term"]} for s, e in GLOSSARY.items() if s != term],
|
||||
}
|
||||
|
|
@ -901,7 +901,7 @@ def about_page(request: Request) -> Response:
|
|||
ctx = {
|
||||
"canonical_path": "/about",
|
||||
"breadcrumb": [("Home", f"{BASE}/"), ("About", None)],
|
||||
"page_title": "About Thermograph — how the weather grades are calculated",
|
||||
"page_title": "About Thermograph: how the weather grades are calculated",
|
||||
"page_description": ("How Thermograph works: ~45 years of ERA5 climate history, a ±7-day seasonal "
|
||||
"window, and empirical percentiles that grade each day relative to its own location."),
|
||||
}
|
||||
|
|
@ -912,7 +912,7 @@ def privacy_page(request: Request) -> Response:
|
|||
ctx = {
|
||||
"canonical_path": "/privacy",
|
||||
"breadcrumb": [("Home", f"{BASE}/"), ("Privacy", None)],
|
||||
"page_title": "Privacy — Thermograph",
|
||||
"page_title": "Privacy | Thermograph",
|
||||
"page_description": ("What Thermograph does and does not collect: no tracking, no ads, "
|
||||
"no account required, and location that never leaves your browser."),
|
||||
}
|
||||
|
|
@ -933,7 +933,7 @@ _HOME_JSONLD = {
|
|||
"operatingSystem": "Web, iOS, Android",
|
||||
"isAccessibleForFree": True,
|
||||
"offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"},
|
||||
"description": ("How unusual is your weather? Any day, anywhere on Earth — graded "
|
||||
"description": ("How unusual is your weather? Any day, anywhere on Earth, graded "
|
||||
"against 45 years of that place's own history."),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ async def _store(email: str, place: str | None, source: str | None) -> None:
|
|||
email,
|
||||
"Confirm your Thermograph digest",
|
||||
"Thanks for signing up for the Thermograph monthly digest.\n\n"
|
||||
"Confirmation links are not active yet — you're on the list, and "
|
||||
"Confirmation links are not active yet, but you're on the list, and "
|
||||
"you'll get a confirmation as soon as they are.\n",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ def _line(card: dict) -> str:
|
|||
tag = " · ".join(p for p in (pct, grade) if p)
|
||||
when = f" ({card['date_label']})" if card.get("date_label") else ""
|
||||
normal_txt = f", normal {normal}" if normal else ""
|
||||
return f"**{display}** — {metric} {val}{normal_txt}{when}" + (f" · {tag}" if tag else "")
|
||||
return f"**{display}**: {metric} {val}{normal_txt}{when}" + (f" · {tag}" if tag else "")
|
||||
|
||||
|
||||
def build_embed(feed: dict) -> dict:
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@ def _compose(sub, event_date, metric, direction, graded):
|
|||
val_txt = f" ({value}{unit})" if value is not None else ""
|
||||
if sub.kind == "forecast":
|
||||
body = (f"Forecast for {event_date}: the {noun} is projected at the "
|
||||
f"{pct:g}th percentile{val_txt} — {grade}.")
|
||||
f"{pct:g}th percentile{val_txt}, {grade}.")
|
||||
else:
|
||||
body = (f"On {event_date}, the {noun} hit the {pct:g}th "
|
||||
f"percentile{val_txt} — {grade}.")
|
||||
f"percentile{val_txt}, {grade}.")
|
||||
return title, body
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ def _metric_entry(metric: str, base: np.ndarray, rec: np.ndarray) -> dict:
|
|||
"key": metric, "label": METRIC_LABELS[metric],
|
||||
"score": score, "mad": div["mad"], "bias": div["bias"],
|
||||
"tier": tier, "class": css, "direction": direction,
|
||||
"grade": tier if score < 15 else f"{tier} — {direction}",
|
||||
"grade": tier if score < 15 else f"{tier}, {direction}",
|
||||
"weight": WEIGHTS[metric], "per_q": div["per_q"],
|
||||
"n_recent": int(rec.size), "n_base": int(base.size),
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ def _annual_entry(metric: str, seasonal: list, history: pl.DataFrame,
|
|||
"key": metric, "label": METRIC_LABELS[metric],
|
||||
"score": score, "mad": round(mad, 1), "bias": round(bias, 1),
|
||||
"tier": tier, "class": css, "direction": direction,
|
||||
"grade": tier if score < 15 else f"{tier} — {direction}",
|
||||
"grade": tier if score < 15 else f"{tier}, {direction}",
|
||||
"weight": WEIGHTS[metric], "per_q": per_q,
|
||||
"n_recent": sum(e["n_recent"] for e in present),
|
||||
"n_base": sum(e["n_base"] for e in present),
|
||||
|
|
@ -286,7 +286,7 @@ def build_scores(history: pl.DataFrame) -> dict:
|
|||
years = history["date"].dt.year()
|
||||
span = int(years.max() - years.min() + 1)
|
||||
if span < MIN_BASELINE_YEARS:
|
||||
return {"unavailable": f"Only {span} years of record here — climate drift "
|
||||
return {"unavailable": f"Only {span} years of record here; climate drift "
|
||||
f"needs at least {MIN_BASELINE_YEARS}."}
|
||||
recent, baseline = recent_baseline_split(history)
|
||||
latest = history["date"].max()
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@
|
|||
location's own climate history.</p>
|
||||
|
||||
<h2>Where the data comes from</h2>
|
||||
<p>The ~45-year daily record — high, low, feels-like, humidity, wind, gust and precipitation —
|
||||
<p>The ~45-year daily record (high, low, feels-like, humidity, wind, gust and precipitation)
|
||||
comes from the <b>ERA5 reanalysis</b> (ECMWF), served via <a href="https://open-meteo.com/" rel="nofollow">Open-Meteo</a>.
|
||||
Because reanalysis is a gridded, model-consistent record, Thermograph works even where there's
|
||||
no weather station — anywhere on the ~4 sq mi grid.</p>
|
||||
no weather station, anywhere on the ~4 sq mi grid.</p>
|
||||
|
||||
<h2>How a day is graded</h2>
|
||||
<p>For each metric and date, Thermograph builds a reference distribution from every historical day
|
||||
within <b>±7 days of that day-of-year</b> — a 15-day seasonal window across all years. The
|
||||
within <b>±7 days of that day-of-year</b>, a 15-day seasonal window across all years. The
|
||||
observed value is placed on that distribution as an <a href="{{ base }}/glossary/percentile">empirical
|
||||
percentile</a>, then mapped to a grade from “Below Normal” through “High” to “Near Record”.</p>
|
||||
<p>Everything is <b>relative to the location</b>: a {{ temp(60) }} day can be “Above Normal” in one place and
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
{% if flavor %}
|
||||
<p class="city-blurb">{{ flavor.extract }}{% if flavor.url %}
|
||||
<a class="blurb-src" href="{{ flavor.url }}" rel="nofollow">— via Wikipedia</a>{% endif %}</p>
|
||||
<a class="blurb-src" href="{{ flavor.url }}" rel="nofollow">via Wikipedia</a>{% endif %}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if today %}
|
||||
<section class="climate-today">
|
||||
<h2>How today compares</h2>
|
||||
<p class="muted">Latest recorded day: {{ today.date }} — each reading placed on {{ display }}'s
|
||||
<p class="muted">Latest recorded day: {{ today.date }}. Each reading placed on {{ display }}'s
|
||||
own ±7-day seasonal distribution.</p>
|
||||
<div class="today-cards">
|
||||
{% for c in today.cards %}
|
||||
|
|
@ -82,14 +82,14 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
<p class="range-note muted">Each bar spans the 10th-percentile daily low to the 90th-percentile daily
|
||||
high — the range most days fall within — coloured cold → hot on a shared
|
||||
high (the range most days fall within), coloured cold → hot on a shared
|
||||
{{ temp(-10) }} to {{ temp(115) }} scale, so the whole year's rhythm reads at a glance.</p>
|
||||
</section>
|
||||
|
||||
<section class="city-travel">
|
||||
<h2>Thinking of visiting {{ name }}?</h2>
|
||||
<p>Trips live and die by the weather. See how {{ name }}'s comfort stacks up against where
|
||||
you live — {{ name }} is pre-loaded, just add your city.</p>
|
||||
you live. {{ name }} is pre-loaded, just add your city.</p>
|
||||
<p><a class="cta" href="{{ compare_url }}">Compare {{ name }}'s comfort with your city →</a></p>
|
||||
</section>
|
||||
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
{% endif %}
|
||||
|
||||
<p class="climate-foot muted">Percentiles compare each day to {{ display }}'s own history, so grades are
|
||||
relative to this location — a “Near Record” day here isn't the same temperature as elsewhere.
|
||||
relative to this location: a “Near Record” day here isn't the same temperature as elsewhere.
|
||||
<a href="{{ base }}/legend">How the grades work →</a></p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<article class="climate-page">
|
||||
<h1>{{ term }}</h1>
|
||||
<p class="lede">{{ body | safe }}</p>
|
||||
<p><a class="cta" href="{{ base }}/">See it live — grade any location's weather →</a></p>
|
||||
<p><a class="cta" href="{{ base }}/">See it live: grade any location's weather →</a></p>
|
||||
<div class="climate-foot">
|
||||
<h2>More terms</h2>
|
||||
<ul class="city-links">
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
(content.home_page), not a child-template {% set %} — the SEO pages already
|
||||
pass `section` that way. #}
|
||||
|
||||
{% block title %}Thermograph — how unusual is your weather?{% endblock %}
|
||||
{% block description %}See how today's weather compares to decades of local climate history for any place on Earth — daily high, low, feels-like, humidity, wind and rain graded by percentile.{% endblock %}
|
||||
{% block title %}Thermograph: how unusual is your weather?{% endblock %}
|
||||
{% block description %}See how today's weather compares to decades of local climate history for any place on Earth. Daily high, low, feels-like, humidity, wind and rain, each graded by percentile.{% endblock %}
|
||||
{% block canonical_path %}/{% endblock %}
|
||||
|
||||
{% block head_extra %}
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
<section id="hero" class="hero">
|
||||
<div class="hero-copy">
|
||||
<h1>How unusual is your weather?</h1>
|
||||
<p class="hero-sub">Any day, anywhere on Earth — graded against 45 years of that place's own history.</p>
|
||||
<p class="hero-sub">Any day, anywhere on Earth, graded against 45 years of that place's own history.</p>
|
||||
</div>
|
||||
|
||||
<div class="hero-card">
|
||||
|
|
@ -138,7 +138,7 @@
|
|||
<ol class="how-steps">
|
||||
<li>We keep 45 years of climate history (ERA5 reanalysis) for your exact ~2-mile grid square.</li>
|
||||
<li>Today gets compared to the same two weeks of the year, every year back to 1980.</li>
|
||||
<li>The result is a percentile and a plain-language grade — Near Record cold to Near Record hot.</li>
|
||||
<li>The result is a percentile and a plain-language grade, from Near Record cold to Near Record hot.</li>
|
||||
</ol>
|
||||
<p class="muted">
|
||||
<a href="{{ base }}/legend">Full methodology →</a>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</nav>
|
||||
<article class="climate-page">
|
||||
<h1>City climates</h1>
|
||||
<p class="lede">Average temperatures by month, all-time records, and how today compares — for
|
||||
<p class="lede">Average temperatures by month, all-time records, and how today compares, for
|
||||
{{ n_cities }} cities across {{ n_countries }} countries. Every day is graded against that
|
||||
location's own ~45 years of climate history.</p>
|
||||
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
return '<li><a href="' + e.href + '">' + esc(e.name) + "</a>" +
|
||||
'<span class="hub-r-country">' + esc(e.country) + "</span></li>";
|
||||
}).join("") + (matches.length > 300
|
||||
? '<li class="hub-empty muted">…and ' + (matches.length - 300) + " more — keep typing to narrow.</li>"
|
||||
? '<li class="hub-empty muted">…and ' + (matches.length - 300) + " more. Keep typing to narrow.</li>"
|
||||
: "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<h2>Your location</h2>
|
||||
<p>Thermograph never looks up your location from your IP address. The only way the site
|
||||
learns where you are is if you press <b>Use my location</b>, which asks your browser for
|
||||
permission — you can decline, and picking a place on the map works just as well.</p>
|
||||
permission. You can decline, and picking a place on the map works just as well.</p>
|
||||
<p>Whichever way you choose a place, the coordinates are sent to the server only as part of
|
||||
the ordinary request for that grid square's climate data, and are not logged beyond the
|
||||
normal web-server request handling every site does. The place you picked is remembered in
|
||||
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
<h2>Analytics</h2>
|
||||
<p>There is no analytics library, no cookies for tracking, and no per-visitor identifier.
|
||||
The server keeps simple aggregate counts — how many people opened a page or tapped a
|
||||
button, and which site referred them — with nothing tying any of it to an individual.</p>
|
||||
The server keeps simple aggregate counts (how many people opened a page or tapped a
|
||||
button, and which site referred them) with nothing tying any of it to an individual.</p>
|
||||
|
||||
<h2>Email</h2>
|
||||
<p>If you sign up for the monthly digest, your address is used for that digest and nothing
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
<article class="climate-page">
|
||||
<h1>{{ display }} weather records</h1>
|
||||
<p class="lede">Record high and low temperatures for <b>{{ display }}</b> — by month, by season, and
|
||||
all-time — with the dates they occurred, across {{ year_range[0] }}–{{ year_range[1] }} of daily
|
||||
<p class="lede">Record high and low temperatures for <b>{{ display }}</b>, by month, by season, and
|
||||
all-time, with the dates they occurred, across {{ year_range[0] }}–{{ year_range[1] }} of daily
|
||||
climate history.{% if all_time.tmax and all_time.tmin %} Its hottest day on record reached
|
||||
{{ temp(all_time.tmax.max) }} on {{ all_time.tmax.max_date }}; its coldest fell to
|
||||
{{ temp(all_time.tmin.min) }} on {{ all_time.tmin.min_date }}.{% endif %}</p>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<section class="climate-records-section">
|
||||
<h2>Records by month</h2>
|
||||
<p>The warmest (▲) and coldest (▼) both the daytime high and the overnight low have ever been in
|
||||
each calendar month — so each column shows its record high <i>and</i> its record low. Tap a
|
||||
each calendar month, so each column shows its record high <i>and</i> its record low. Tap a
|
||||
month for its full averages and typical range.</p>
|
||||
<div class="table-wrap">
|
||||
<table class="normals-table records-table records-ext">
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
<section class="climate-records-section">
|
||||
<h2>Records by season</h2>
|
||||
<p>The warmest (▲) and coldest (▼) both the daytime high and the overnight low have reached in each
|
||||
meteorological season ({{ hemisphere }} Hemisphere — each a three-month span).</p>
|
||||
meteorological season ({{ hemisphere }} Hemisphere, each a three-month span).</p>
|
||||
<div class="table-wrap">
|
||||
<table class="normals-table records-table records-ext">
|
||||
<thead><tr><th>Season</th><th>Daytime high</th><th>Overnight low</th></tr></thead>
|
||||
|
|
|
|||
Loading…
Reference in a new issue