Drop the ' · Calendar' / ' · Day' page indicators from the subpage headers - at the wordmark's size they wrapped the lockup to two lines on phones, and the active nav pill already names the page. On mobile the hamburger is now position:fixed at the viewport's top-right so nav follows the user down the page (below the filter-sheet scrim and map modal); the brand row reserves the corner so the lockup can't slide beneath it. Claude-Session: https://claude.ai/code/session_01KdTZCjpLeD26ZbXe6ApjpR
175 lines
10 KiB
HTML
175 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Thermograph — compare comfort</title>
|
|
<meta name="description" content="Compare how well two or more places hit your comfort temperature over any date range, side by side, each graded against its own ~45-year climate history." />
|
|
<meta name="theme-color" content="#f0803c" />
|
|
<!-- Link previews (Discord, Slack, iMessage…). The server fills the og:url /
|
|
og:image origins in from this request's scheme://host + base path —
|
|
crawlers need absolute URLs and don't run JS. -->
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:site_name" content="Thermograph" />
|
|
<meta property="og:title" content="Thermograph — compare comfort" />
|
|
<meta property="og:description" content="Compare how well two or more places hit your comfort temperature over any date range, side by side, each graded against its own ~45-year climate history." />
|
|
<meta property="og:url" content="__ORIGIN__/compare" />
|
|
<meta property="og:image" content="__ORIGIN__/logo.png?v=2" />
|
|
<meta property="og:image:width" content="512" />
|
|
<meta property="og:image:height" content="512" />
|
|
<meta property="og:image:alt" content="Thermograph logo" />
|
|
<meta name="twitter:card" content="summary" />
|
|
<link rel="canonical" href="__ORIGIN__/compare" />
|
|
<link rel="icon" href="favicon.svg" type="image/svg+xml" />
|
|
<link rel="icon" href="favicon-48.png" type="image/png" sizes="48x48" />
|
|
<link rel="icon" href="favicon-32.png" type="image/png" sizes="32x32" />
|
|
<link rel="icon" href="favicon-16.png" type="image/png" sizes="16x16" />
|
|
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
|
<link rel="manifest" href="manifest.webmanifest" />
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<link rel="stylesheet" href="style.css" />
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<div class="brand">
|
|
<div>
|
|
<h1><span class="logo"><svg viewBox="0 0 512 512" width="28" height="28" aria-hidden="true"><rect x="32" y="32" width="448" height="448" rx="96" fill="#10141B" stroke="#fff" stroke-opacity=".08" stroke-width="4"/><rect x="64" y="170" width="384" height="48" rx="8" fill="#27131C"/><rect x="64" y="222" width="384" height="48" rx="8" fill="#38322E"/><rect x="64" y="274" width="384" height="48" rx="8" fill="#1A2D27"/><rect x="64" y="326" width="384" height="48" rx="8" fill="#26333F"/><rect x="64" y="378" width="384" height="48" rx="8" fill="#18293A"/><line x1="64" y1="132" x2="448" y2="132" stroke="#46586E" stroke-width="8" stroke-dasharray="26 20"/><path d="M64 410H126V386H160" fill="none" stroke="var(--cold)" stroke-width="34"/><path d="M160 403V352H244V368H282" fill="none" stroke="var(--cool)" stroke-width="34"/><path d="M282 385V320H312" fill="none" stroke="var(--normal)" stroke-width="34"/><path d="M312 337V248H338" fill="none" stroke="var(--warm)" stroke-width="34"/><path d="M338 265V196H366" fill="none" stroke="var(--hot)" stroke-width="34"/><path d="M366 213V132H396" fill="none" stroke="var(--very-hot)" stroke-width="34"/><rect x="382" y="100" width="64" height="64" rx="12" fill="var(--rec-hot)" stroke="#10141B" stroke-width="12"/></svg></span>Thermograph</h1>
|
|
<p class="tag">Which place best hits your comfort temperature over a date range</p>
|
|
</div>
|
|
<details class="nav-menu">
|
|
<summary class="nav-toggle" aria-label="Menu"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg></summary>
|
|
<div class="nav-panel">
|
|
<nav class="view-nav" aria-label="Views">
|
|
<a href="./" data-view="map">Weekly</a>
|
|
<a href="calendar" data-view="calendar">Calendar</a>
|
|
<a href="day" data-view="day">Day Detail</a>
|
|
<a href="compare" data-view="compare" class="active">Compare</a>
|
|
<a href="climate">Climate</a>
|
|
<a href="alerts">Alerts</a>
|
|
</nav>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</header>
|
|
|
|
<main>
|
|
<!-- Locations to line up against each other. -->
|
|
<section class="controls">
|
|
<div class="cmp-locs">
|
|
<span class="cal-filter-label">Locations</span>
|
|
<ul id="cmp-loc-list" class="cmp-loc-list"></ul>
|
|
<div class="cmp-loc-actions">
|
|
<button type="button" id="cmp-add" class="find-btn"></button>
|
|
<button type="button" id="cmp-refresh" class="cmp-refresh-btn" hidden>Refresh comparison ↻</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- The comfort target, what temperature to judge by, the tolerance band, and
|
|
the date range. Comfort/band/basis recompute instantly (no refetch); only
|
|
the date range or the location set trigger a data load. -->
|
|
<!-- Comfort/tolerance target — the primary knob, kept inline above the results
|
|
(never inside the mobile filter sheet). Recomputes the ranking instantly. -->
|
|
<div id="cmp-comfort" class="cmp-comfort-wrap" hidden>
|
|
<div class="cmp-range-labels">
|
|
<span class="cmp-rl cmp-rl-comfort">Comfort <b id="cmp-comfort-val"></b></span>
|
|
<span class="cmp-rl cmp-rl-tol">Tolerance <b id="cmp-tol-val"></b></span>
|
|
</div>
|
|
<div class="cmp-ticks" id="cmp-ticks" aria-hidden="true">
|
|
<span class="cmp-tick tol" id="cmp-tick-tlo"></span>
|
|
<span class="cmp-tick" id="cmp-tick-lo"></span>
|
|
<span class="cmp-tick" id="cmp-tick-hi"></span>
|
|
<span class="cmp-tick tol" id="cmp-tick-thi"></span>
|
|
</div>
|
|
<div class="dual-range quad-range" id="cmp-slicer">
|
|
<div class="dual-track">
|
|
<span class="dual-fill dual-fill-tol" id="cmp-fill-tol"></span>
|
|
<span class="dual-fill" id="cmp-fill"></span>
|
|
</div>
|
|
<input id="cmp-tlo" type="range" min="30" max="100" step="1" class="thumb-tol" aria-label="Tolerance range lower bound" />
|
|
<input id="cmp-lo" type="range" min="30" max="100" step="1" aria-label="Comfort range lower bound" />
|
|
<input id="cmp-hi" type="range" min="30" max="100" step="1" aria-label="Comfort range upper bound" />
|
|
<input id="cmp-thi" type="range" min="30" max="100" step="1" class="thumb-tol" aria-label="Tolerance range upper bound" />
|
|
</div>
|
|
<span class="hint">Inner handles set your comfort range; outer handles set the tolerance range. Days in tolerance still count toward the score, scaled by how far past comfort they fall.</span>
|
|
<!-- Which temperature to judge each day by — a scoring control, so it sits with
|
|
the comfort slider above the results, not in the filter sheet. -->
|
|
<div class="cmp-basis-block">
|
|
<span class="cal-filter-label">Judge each day by its</span>
|
|
<div class="metric-toggle" id="cmp-basis" role="group" aria-label="Temperature to compare">
|
|
<button type="button" data-basis="tmax" class="active">High</button>
|
|
<button type="button" data-basis="mean">Mean</button>
|
|
<button type="button" data-basis="tmin">Low</button>
|
|
<button type="button" data-basis="feels">Feels</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="cmp-params" class="cmp-params" hidden>
|
|
<div class="cmp-param cmp-season" id="cmp-season">
|
|
<span class="cal-filter-label">Time of year</span>
|
|
<div class="cmp-season-dd" id="cmp-season-dd"></div>
|
|
<span class="hint">Count only days in these seasons/months — re-ranks instantly.</span>
|
|
</div>
|
|
|
|
<div class="cmp-param cmp-range cal-range" id="cmp-range">
|
|
<div class="cal-range-head">
|
|
<span class="cal-filter-label">Date range</span>
|
|
<span class="hint">any span; longer loads take a moment</span>
|
|
</div>
|
|
<label>From <input id="cmp-start" type="month" /></label>
|
|
<label>To <input id="cmp-end" type="month" /></label>
|
|
<span class="hint">Editing the range arms Load — tap it to reload.</span>
|
|
<button type="button" id="cmp-refresh-sheet" class="cmp-refresh-btn" hidden>Load / Refresh ↻</button>
|
|
</div>
|
|
|
|
<!-- A synced copy of the "Distribution by" selector (below), for the phone
|
|
sheet; buttons are cloned from the inline one in JS. Hidden on desktop. -->
|
|
<div class="cmp-param cmp-dist-metric-block">
|
|
<span class="cal-filter-label">Distribution by</span>
|
|
<div class="metric-toggle" id="cmp-dist-metric-sheet" role="group" aria-label="Distribution metric (in filters)"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="cmp-head" class="cal-head" hidden></div>
|
|
|
|
<div class="placeholder" id="cmp-placeholder">
|
|
<p>Add two or more places to see which one best matches your comfort temperature
|
|
across a date range — the share of days that land in your comfort band, how
|
|
often it runs colder or warmer, and by how much.</p>
|
|
</div>
|
|
|
|
<!-- Baseline: every place's typical temperature on one shared axis, so their
|
|
baselines line up against each other and the shaded comfort range. -->
|
|
<section id="cmp-baseline" class="cmp-baseline" hidden></section>
|
|
|
|
<div id="cmp-results" class="cmp-results"></div>
|
|
|
|
<!-- Climate distribution, independent of the comfort filter: how each place's
|
|
days spread across a metric's Record-Low→Record-High categories, mirroring
|
|
the calendar's totals strip. Its own metric + share/count toggles. -->
|
|
<section id="cmp-dist" class="cmp-dist" hidden>
|
|
<div class="ct-head">
|
|
<div class="cmp-dist-controls">
|
|
<span class="cal-filter-label">Distribution by</span>
|
|
<div class="metric-toggle" id="cmp-dist-metric" role="group" aria-label="Distribution metric">
|
|
<button type="button" data-metric="tmax" class="active">High</button>
|
|
<button type="button" data-metric="tmin">Low</button>
|
|
<button type="button" data-metric="feels">Feels</button>
|
|
<button type="button" data-metric="humid">Humid</button>
|
|
<button type="button" data-metric="wind">Wind</button>
|
|
<button type="button" data-metric="gust">Gust</button>
|
|
<button type="button" data-metric="precip">Precip</button>
|
|
<button type="button" data-metric="dsr">Dry streak</button>
|
|
</div>
|
|
</div>
|
|
<label class="ct-count-toggle"><input type="checkbox" id="cmp-dist-count" /> Show count</label>
|
|
</div>
|
|
<div id="cmp-dist-body" class="cmp-dist-body"></div>
|
|
</section>
|
|
</main>
|
|
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<script type="module" src="compare.js"></script>
|
|
</body>
|
|
</html>
|