Commit Graph
101 Commits
Author SHA1 Message Date
Nate EmmertandClaude Sonnet 5.5 dee245ea27 Dashboard: always show Settings link; non-admins get an explanation of their role
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 07:34:32 -04:00
Nate EmmertandClaude Sonnet 5.5 2efc945192 Radar: switch to RainViewer (IEM blocks heavy tile use), cleaner Map tab
Publish Container / publish (push) Successful in 2m40s
- /api/radar/times serves RainViewer frames (cached 2 min), IEM NEXRAD only as fallback;
  sources honour maxNativeZoom so tiles overzoom instead of going blank
- Map tab opens with radar + location dot only; wind/AQI/alerts/temp/sun/lightning are opt-in,
  readout chips follow their toggles
- Bolder location dot
- Satellite (GIBS) layer: new storage key, never persisted by storm taps, radar always draws above it

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:38:00 -04:00
Nate EmmertandClaude Sonnet 5.5 13985344ed Storm cards show live GOES infrared satellite; replace the dead RainViewer satellite toggle
Publish Container / publish (push) Successful in 2m19s
RainViewer's satellite feed is empty, so the Clouds toggle never drew anything and ground
radar doesn't reach open ocean. Use NASA GIBS GOES-West/East infrared tiles instead,
auto-enabled when flying to a storm, default off otherwise.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:01:03 -04:00
Nate EmmertandClaude Sonnet 5.5 a185d10e1c Fix storm cards not flying to the storm: stop waiting on the one-shot map 'load' event
Publish Container / publish (push) Successful in 2m34s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:52:59 -04:00
Nate EmmertandClaude Sonnet 5.5 fda8dca435 Performance: stop iPhone freezes (blur over live map, runaway animation, eager charts)
Publish Container / publish (push) Successful in 2m57s
Main app
- No backdrop-filter over the live map, animated sky, or sticky headings (it re-blurs every
  frame; on iPhone that is a classic stutter/lock-up); top/bottom bars keep a light 8px blur
- Sky effect only draws while the hero is on screen and the Now tab is active, ~30fps cap,
  fewer particles on phones; fixed a stale animation-frame id that could stop restarts

Dashboard
- Charts are built only when the Charts tab is opened (was ~11 charts on every page load),
  and the 2-minute refresh no longer rebuilds them in the background
- On phones: max 360 points per chart (was 720), no entry animation, device pixel ratio capped at 2
- Lighter header blur, none on small buttons/cards

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:29:14 -04:00
Nate EmmertandClaude Sonnet 5.5 dde59e3865 Station tab: explain what the station is
Publish Container / publish (push) Successful in 2m13s
- 'What is this station?' card: a personal weather station measuring real conditions on site
  (not a forecast), how it differs from the Now tab, update cadence, what Live/Offline mean
- Lists the instruments this station actually reports (temp/humidity, wind, rain, pressure,
  sun, indoor), using the station's real name
- Open for new visitors, remembers once closed; empty state and Now-tab badge/tab hover explain it too

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:16:33 -04:00
Nate EmmertandClaude Sonnet 5.5 eaff2f55c8 Location: say why it failed, retry once, show permission status
Publish Container / publish (push) Successful in 2m15s
The ⌖ button reported 'Location access denied' for every failure, including timeouts and
no-GPS-fix errors that have nothing to do with permission.

- Specific messages for denied / no fix / timeout, with the exact iPhone steps (Safari tab vs
  installed web app) and the error code for diagnosis
- One patient high-accuracy retry for slow or cold GPS fixes (a real denial is not retried)
- Live permission status line under the search row (allowed / not asked / blocked)
- Mentions Safari content blockers as a possible cause

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:07:19 -04:00
Nate EmmertandClaude Sonnet 5.5 0cbebfef2a Cache-proof asset URLs and inline iOS touch icon
Publish Container / publish (push) Successful in 2m42s
A reverse proxy in front of the app serves stale copies of static files for hours (live app.js and
sw.js were old next to new HTML). iOS also showed a letter tile (N / S) because its separate
icon download failed.

- HTML pages are served through a versioner: every local script/stylesheet/icon/manifest gets a
  content-hash query (app.js?v=…), so any change is a URL no proxy or phone has cached
- Service worker URL versioned too; SW offline lookups tolerate the query string; cache v15
- The 180px apple-touch-icon is embedded in each page as a data: URI, so the Home Screen icon
  no longer depends on a second network request

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:33:40 -04:00
Nate EmmertandClaude Sonnet 5.5 f21c91527c Serve PWA icons from fresh /icons/v2/ URLs with every iOS size
Publish Container / publish (push) Successful in 2m43s
iOS showed a letter tile ('N') when adding to the Home Screen. The live files were fine, but a
reverse proxy in front of the app serves static files with a long cache lifetime (live icon.svg
and sw.js were stale) and iOS remembers a failed icon per URL.

- New versioned URLs no proxy/phone has cached; old paths kept for existing installs
- apple-touch-icon declared at 180/167/152/120 (opaque 8-bit RGB PNGs) for app and dashboard
- 180px icon also listed in both manifests; notification icons and root fallbacks use v2
- Service worker cache bumped

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:22:05 -04:00
Nate EmmertandClaude Sonnet 5.5 19479daece Dashboard pages: iOS icon + Home Screen title everywhere; root icon fallbacks
Publish Container / publish (push) Successful in 2m11s
- setup/recover/settings pages now declare the dashboard touch icon and 'Station' title
- /apple-touch-icon.png, /apple-touch-icon-precomposed.png and /favicon.ico serve real icons
  (iOS falls back to these when a page declares none; they used to 404/204)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:15:19 -04:00
Nate EmmertandClaude Sonnet 5.5 023e6cb03c New PWA icons: slate/blue weather icon, distinct dashboard icon, safe-zone maskable
Publish Container / publish (push) Successful in 1m59s
- Redrawn sun-and-cloud icon in the current palette; artwork sits inside the maskable safe zone
  (the old one was clipped by round/squircle masks and used the old warm colours)
- Separate 'any' and 'maskable' manifest entries; opaque iOS touch icons
- Station Dashboard gets its own chart icon so both installed apps are distinguishable
- Vector favicon + PNG fallback; icons verified served by both manifests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:13:01 -04:00
Nate EmmertandClaude Sonnet 5.5 72a4a3fe38 Alerts tab: fix hurricane/tropical storm bugs; rich alert cards matching the dashboard
Publish Container / publish (push) Successful in 2m44s
Hurricane / tropical storm fixes
- NHC intensity is in knots: show real mph (80 kt = 92 mph) instead of mislabelled 'mph'
- Real Saffir-Simpson category from wind (was always cat 1); subtropical, post-tropical and
  potential-cyclone types no longer shown as 'depression'; each storm shows movement
  (direction + mph, previously a non-existent field), distance from you, update time, advisory link
- Forecast track points coloured by their own forecast strength (not the current class)
- Map click handlers registered once (popups stacked on every refresh); overlays wait for the
  map to settle instead of silently not drawing while tiles load; stale renders superseded
- Subtropical/tropical advice added to alert guidance; escaped storm names

Alert cards (active alerts only)
- What it's for, area, window, time remaining, plain-language meaning, what to do, and a
  Full details expander (headline, text, instructions, severity/urgency/certainty, issuer)
- No longer drops alerts beyond 6 per severity group; expired alerts are filtered out
- Shared plain-language alert glossary (alert-info.js, 64 products incl. tropical and surge)
  now used by both the app and the dashboard history

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:00:41 -04:00
Nate EmmertandClaude Sonnet 5.5 8252017417 Map tab: full-bleed map with floating glass controls (Apple Weather style)
Publish Container / publish (push) Successful in 2m58s
- Map fills everything between the top bar and bottom nav; no page scroll on this tab
- Floating round controls (layers, my location, full screen), readout chips top-left,
  layers sheet beside the controls, weather summary + radar timeline floating at the bottom
- Safe-area aware in full-screen mode; zoom buttons tucked away on touch devices

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:48:13 -04:00
Nate EmmertandClaude Sonnet 5.5 4f47d67a7e Map tab: much bigger map with its own remembered view
Publish Container / publish (push) Successful in 2m12s
- Map fills the screen (was a 56vh strip); timeline and details sit below it
- No longer snaps back to the main-page radar's location/zoom on every refresh or tab switch;
  starts as a wider regional view, remembers pan/zoom, and recentres only when the location changes
- New 'My location' button

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:43:04 -04:00
Nate EmmertandClaude Sonnet 5.5 acdcd6a2c5 Log official NWS observations for a reference ZIP and overlay them on the dashboard
Publish Container / publish (push) Successful in 2m33s
- Resolves ZIP (default 24550) to the nearest NWS observation station; logs every observation
  (normalised imperial values + raw METAR), back-fills ~7 days, snapshots the hourly forecast
  every 3h, and logs alerts for that point
- Chart overlay (temp, humidity/dew point, wind, pressure) with an NWS toggle in the History bar
- 'Official NWS observation' card on the Now tab comparing against your station
- Settings: change the reference ZIP and see logging status
- Exact-unit conversions for NWS values (verified against known conversions)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:41:02 -04:00
Nate EmmertandClaude Sonnet 5.5 5ed673bacc Install-as-app guide and iPhone safe-area support
Publish Container / publish (push) Successful in 2m51s
- Install banner (phones), Settings guide and dialog with iPhone/iPad and Android steps,
  native Install button where supported; steps also on the dashboard Account page
- apple-touch-icon now a PNG (iOS ignores SVG icons)
- Shared pwa-safe.css: dark cap behind the status bar/Dynamic Island in the installed app,
  inset-aware offline banner, pull-to-refresh, bottom bars, full-screen map, dialogs
- Landscape-aware content gutters; measured top-bar height; viewport-fit=cover on every page

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:34:22 -04:00
Nate EmmertandClaude Sonnet 5.5 114386a1b2 Alert history: say what each alert is for, where, and when
Publish Container / publish (push) Successful in 3m33s
- Plain-language meaning for common NWS products, shown in the row and expanded view
- Details column: reason, area, severity, effective window; click for full text/instructions
- New alerts log area, severity, urgency, certainty and sender
- Older entries are filled in from NWS by alert id (cached in data/alert-details.json);
  alerts NWS no longer serves fall back to the built-in meaning

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:28:28 -04:00
Nate EmmertandClaude Sonnet 5.5 72d813bd61 Records: month and year records with the period as the headline
Publish Container / publish (push) Successful in 3m55s
- Wettest/driest/hottest/coldest/windiest month and wettest/hottest/coldest/windiest year,
  each naming the period (e.g. 'September 2026') and flagging partial periods
- Average-based records prefer complete periods; counterparts say what they're waiting for
- 'Records by calendar month (any year)' table with the date/year of each record

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:21:55 -04:00
Nate EmmertandClaude Sonnet 5.5 6e285bfef1 Show the first-recorded date on the All history button tooltip
Publish Container / publish (push) Successful in 2m54s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:17:46 -04:00
Nate EmmertandClaude Sonnet 5.5 00336c6ce1 Add 'All' history range to the dashboard and pressure tendency chart
Publish Container / publish (push) Successful in 2m45s
- /api/station/history?range=all returns everything on disk, bucketed (cached 60s)
- Year-aware axis labels for 1y/2y/3y/All
- Pressure tendency widens its change window to the bucket size on long ranges and says so

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:17:33 -04:00
Nate EmmertandClaude Sonnet 5.5 fc390b0bb1 Pressure tendency chart: own range and change-window controls
Publish Container / publish (push) Successful in 2m28s
Range: same as page / 6h / 24h / 2d / 7d / 30d. Change over: 1h / 3h / 6h / 12h / 24h.
Choices persist in localStorage.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:16:05 -04:00
Nate EmmertandClaude Sonnet 5.5 74198330d9 Fix mouse-wheel scrolling in the main app and the dashboard sun arc
Publish Container / publish (push) Successful in 2m55s
- overscroll-behavior moved from <body> to <html>: with html+body both overflow-x:hidden,
  body is a scroll container and the rule blocked wheel scrolling from reaching the page
- sunTimes returned the neighbouring day's sunrise/sunset (julian-day rounding), so midday
  looked like night; align results to the requested local day

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:12:41 -04:00
Nate EmmertandClaude Sonnet 5.5 a9fc20cef4 Let the mouse wheel scroll the page over charts and the embedded radar
Publish Container / publish (push) Successful in 3m16s
Chart zoom now needs Ctrl+scroll (or pinch); the embedded radar uses cooperative gestures.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:09:19 -04:00
Nate EmmertandClaude Sonnet 5.5 fd61e35b56 Redesign main app: slim top bar, dynamic sky hero, nowcast, scrub chart, unified palette
- One slate/blue palette across the app, dashboard, account/login pages (data colours
  stay orange = warm, blue = cool on the dashboard)
- Slim sticky top bar with location chip, gear (settings) and ? (learn); 4-tab nav
  (Now, Station, Map, Alerts) with a thumb-reach bottom bar on phones
- Hero sky gradient by condition/time with rain, storm, snow and star effects
  (respects reduced motion); keeps the searched city and badges when temps come from your station
- One-line summary, 'Next 2 hours' bars and rain countdown from 15-minute precipitation,
  rain/cold-aware 'Bring' chips; yesterday + 'vs usual' context from the station
- Scrubbable hourly chart (temp, rain chance, wind), 7-day range bars, AQI gauge,
  details tiles instead of drawers, taller radar with location marker + alert polygons
- Skeleton loading instead of a full-screen spinner, sticky section headers, safe areas
- Server: minutely_15 precipitation, public /api/station/summary

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:56:18 -04:00
Nate EmmertandClaude Sonnet 5.5 1830fb2e2b Merge /conditions into the app as a Station tab
- New Station tab (top tabs, bottom nav, swipe order) carrying the old /conditions look:
  radar-ring hero, condition pill, wind compass, atmosphere/precip/solar cards, indoor
- Scoped sl-* styles and station-live.js; units follow the app's metric/imperial setting
- Empty/error states when no station is connected
- /conditions now 301-redirects to /?tab=station; removed conditions.html,
  /api/conditions/public and the old My Station drawer
- /api/ambient-config also returns the station name
- Dashboard and settings links updated; SW cache v8; manifest shortcut for Station
- Drops an indoor-temp block in applyStationOverlay that referenced an out-of-scope helper

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:45:47 -04:00
Nate EmmertandClaude Sonnet 5.5 1566ac2897 Add user management with admin and viewer roles
- data/users.json store; existing single account migrates to first admin
- Roles: admin (settings, import, users) and viewer (read-only, own password)
- Live role/disabled lookup; per-user session epoch so password changes,
  resets and disabling sign that user out everywhere
- Login brute-force lockout (5 fails -> 5 min), constant-time unknown-user check
- /api/users CRUD with last-admin and self-lockout safeguards
- Account page (own password + admin user management); role-aware header
- Min password length 8; recovery token resets the primary admin and clears lockouts

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:34:13 -04:00
Nate EmmertandClaude Sonnet 5.5 b3f1061f5c Keep dashboard panels permanently expanded
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:27:20 -04:00
Nate EmmertandClaude Sonnet 5.5 1ad2dbb860 Redesign dashboard: tabs, insights, rain, sun/moon, zoomable charts
- Tab bar (bottom nav on phones) splitting Now / Charts / Rain / Records / Insights
- Unified tiles with vs-yesterday deltas, hero 24h trace, wind compass, today hi/lo
- Highlights chips, sun & moon card, station health card
- Charts: min/max envelope for long ranges (server-side bucketing), pinch/wheel zoom,
  pressure tendency, indoor vs outdoor, clear-sky solar overlay
- Rain tab: daily + cumulative, monthly totals; calendar heatmaps (temp/rain/gust)
- Insights: period trends, station normals, diurnal range, coverage, seasonal wind roses
- Server: /api/station/daily, history ?points= bucketing, 2d range, daily avg + wind
  histogram aggregates; fix dry days never recording rain=0

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:25:08 -04:00
Nate EmmertandClaude Sonnet 5.5 a97d104d14 Persistent station records, backups, and iPhone-friendly dashboard
- Keep per-day extremes in data/records.json (merge-only) and derive all-time,
  notable-day, monthly and yearly records from it; rebuild from raw files at startup
- Use station maxdailygust for true gust extremes
- Add /api/station/backup.jsonl, records-backup.json and records/rebuild
- Dashboard: safe-area insets, 44px touch targets, scrollable nav/range bars,
  chart touch-action, standalone PWA manifest + apple meta tags

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:14:25 -04:00
Nate EmmertandClaude Sonnet 5.5 528dec753d Make dashboard alerts short with click-to-expand full details
Publish Container / publish (push) Successful in 2m50s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 11:45:50 -04:00
Nate EmmertandClaude Sonnet 4.6 fc93079109 Fix hurricane overlay ordering and map-load guard
Publish Container / publish (push) Successful in 2m52s
- Move renderHurricaneOverlay call to after track layers so position
  circles render on top of the track line and dots
- Add map.loaded() guard to avoid overlay being silently skipped
  if the map style hasn't finished initializing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 10:19:18 -04:00
Nate EmmertandClaude Sonnet 4.6 3af4c1df4b Add NHC forecast track to hurricane click-to-map
Publish Container / publish (push) Successful in 2m6s
- Parse NHC forecast advisory text (FORECAST VALID / OUTLOOK VALID lines)
  to extract real forecast positions at 9–117h intervals with wind speeds
- Render forecast track as dashed line + clickable dots (wind on click)
- Auto-fit map bounds to show the full 5-day track after loading
- Fix buildStyle to use OpenFreeMap vector tile URLs without API key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 10:11:22 -04:00
Nate EmmertandClaude Sonnet 4.6 8b9d3639af Fix map basemap tiles and add hurricane click-to-map feature
Publish Container / publish (push) Successful in 2m18s
- Replace CARTO basemap tiles (now require API key) with OpenFreeMap
  vector tiles (positron for light, liberty for dark) — no key needed
- Add click handlers on hurricane panel cards to fly to storm on map
- Add flyToHurricane(): switches to map tab, enables hurricane overlay,
  flies to storm coords, shows popup with storm details
- Add /api/hurricanes/track proxy to fetch NHC GIS 5-day forecast track
  line and render it as a dashed overlay on the map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 09:52:35 -04:00
Nate EmmertandClaude Sonnet 4.6 5f7e490a6e Fix NWS alerts not showing when no location is configured
Publish Container / publish (push) Successful in 1m55s
- Show a prompt linking to Settings instead of silently hiding the
  alerts section when no lat/lon is saved
- Clear the alert cache when location is saved so alerts appear
  immediately without waiting for the 5-minute cache to expire

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:20:31 -04:00
Nate EmmertandClaude Sonnet 4.6 47f60e72f7 Move all settings to dedicated /dashboard/settings page
Publish Container / publish (push) Successful in 2m22s
Extracts API keys, alert thresholds, station name/location, data
export/import, and password change into a standalone settings page.
Dashboard gains a Settings nav link; the accordion at the bottom
is removed along with its now-orphaned JS and CSS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:08:16 -04:00
Nate EmmertandClaude Sonnet 4.6 97dfae86ab Add alert history dashboard endpoint and UI panel
Publish Container / publish (push) Successful in 2m33s
GET /api/dashboard/alert-history?days=N reads daily .jsonl files from
data/alerts/ and returns entries newest-first. Dashboard gets a lazy-loaded
collapsible panel with a table showing time, type (NWS/threshold badge),
event name, and details, with 7d/30d/90d range selector.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:01:41 -04:00
Nate EmmertandClaude Sonnet 4.6 826bb0f606 Add comprehensive dashboard polish: animations, blur, gradients, skeleton
Visual enhancements:
- Sticky header: backdrop-filter blur + box-shadow on scroll
- Live green pulsing dot next to Updated timestamp
- Section cards: gradient border (accent→border→cool via padding-box trick)
- Stat tiles: hover lift (translateY -2px + shadow)
- Skeleton shimmer on all stat tiles until first data arrives
- Value flash animation (fade+slide up) on every data refresh
- Hero temperature: count-up animation when value changes
- Fix set() to preserve trend arrow spans (was being wiped by textContent=)
- Wind rose petals: entrance animation growing in over 650ms
- Chart cards + today bar: hover lift
- Records panel: gold border + ★ badge on records set within last 30 days
- Range/refresh/settings buttons: already had press+glow from prior commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 16:03:19 -04:00
Nate EmmertandClaude Sonnet 4.6 70eda46b85 Apply button polish to all dashboard interactive elements
Range buttons, refresh, and settings action buttons now get:
- backdrop-filter: blur(10px) frosted glass base
- cubic-bezier(.2,0,0,1) iOS-style easing
- box-shadow glow ring on hover
- scale(0.95) press effect on :active

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:54:34 -04:00
Nate EmmertandClaude Sonnet 4.6 344f0dd48e Add press effect, glow, arrow slide, easing, and backdrop blur to nav buttons
- :active scale(0.95) press feel on all nav buttons
- box-shadow glow ring on hover (accent @ 20% opacity)
- cubic-bezier(.2,0,0,1) iOS-style snap easing on all transitions
- backdrop-filter: blur(10px) frosted glass base on all buttons
- Dashboard → arrow wraps in <span class="arr"> and slides 2px right on hover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:51:37 -04:00
Nate EmmertandClaude Sonnet 4.6 3c927b3e27 Use semi-transparent accent fill on nav button hover
color-mix(accent 18%, transparent) keeps text readable and gives a
ghost-button tint instead of a full solid fill.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:49:03 -04:00
Nate EmmertandClaude Sonnet 4.6 e4a5a9c4bb Style nav links as buttons across all three pages
Replace plain text/opacity links with bordered pill buttons that fill
with accent color on hover — consistent across main app, conditions,
and dashboard headers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:47:01 -04:00
Nate EmmertandClaude Sonnet 4.6 f67e38857e Improve navigation between main app, conditions, and dashboard
- Main app: split tagline into attribution + Station/Dashboard nav pills (always visible, styled with border/hover)
- Conditions page: add Dashboard → link and ← App back-link in header
- Dashboard: add Conditions link, rename App → ← Weather in header nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:43:26 -04:00
Nate EmmertandClaude Sonnet 4.6 2986301599 Fix wind direction rose invisible on iOS (Retina DPR bug)
drawWindRose used canvas.width (physical pixels) for coordinates while
the context was already pre-scaled by devicePixelRatio. On iPhones
(dpr=2/3) this placed the entire rose off-screen. Fix by dividing by
dpr to get CSS dimensions before computing cx/cy/R.

Also make sWindDir stat always show a value ('—' fallback when winddir
is null) and add null guards on sEventRainTile/sTotalRainTile to
prevent a silent throw from aborting updateLatest() early.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:38:16 -04:00
Nate EmmertandClaude Sonnet 4.6 0d00c7f6ab Restore indoor sensor display and restructure dashboard layout
- Restore tempinf/humidityin tiles from PWS data on index.html (removed
  with thermostat cleanup but still available from Ambient station)
- Dashboard: replace two flat secondary-stat grids with labeled section
  cards — Wind, Precipitation, Climate, Indoor — for clearer visual
  hierarchy and category separation
- Indoor section card includes Ecobee portal link; appears only when
  station reports indoor sensor data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 10:07:17 -04:00
Nate EmmertandClaude Sonnet 4.6 e133781760 Remove thermostat/indoor sensor integration
Ecobee API is closed to new developer registrations and iOS sub-daily
automations are no longer available, making the HomeKit push approach
unworkable. Removes all related code:

- server.js: HomeKit push endpoints, token management, data files
- dashboard.html: thermostat section card, indoor stat tiles, indoor
  charts, HomeKit settings panel, HVAC badge CSS, all related JS
- index.html: Indoor Temp stat card
- app.js: indoor sensor display logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 09:19:21 -04:00
nmemmertandClaude e8bb117568 Add thermostat integration via HomeKit push (iOS Shortcuts) (#5)
* Add Ecobee thermostat integration to dashboard

- Server: PIN-based OAuth flow to authorize Ecobee access without
  exposing redirect URIs; tokens stored server-side and auto-refreshed
- Server: /api/ecobee/config, /api/ecobee/auth/pin,
  /api/ecobee/auth/complete, /api/ecobee/data, /api/ecobee/runtime
  endpoints behind dashboard auth
- Dashboard: Ecobee section card showing indoor temp, humidity,
  heat/cool setpoints, HVAC mode, equipment status badge, and
  per-sensor temperature readings from remote sensors
- Dashboard: stacked bar chart of daily heating/cooling runtime hours
  for the past 7 days
- Dashboard: Ecobee setup panel with API key entry and step-by-step
  PIN authorization flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMhuFaecxraQzUPN4h9nsB

* Replace ecobee API integration with HomeKit push endpoint

Ecobee removed public developer API access, so pivot to HomeKit:
- Add POST /api/homekit/push accepting thermostat data from iOS Shortcuts
- Add GET /api/homekit/data returning latest reading to dashboard
- Add GET /api/homekit/config and POST /api/homekit/config/regenerate for token management
- Auto-generate auth token on first run, persist to data/homekit-config.json
- Auto-convert Celsius→Fahrenheit if temp < 50 (HomeKit always returns Celsius)
- Update dashboard section card to show temp, setpoints, humidity, mode, HVAC state
- Replace ecobee settings panel with push URL, token copy, and Shortcut setup instructions
- Remove runtime chart (not available without API access)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-23 08:24:14 -04:00
Nate EmmertandClaude Sonnet 4.6 151e3c9202 Fix wind direction display wrapping on iPad
Move wind direction to its own line below "mph" so it doesn't
wrap or get clipped on narrow stat tiles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-20 10:48:09 -04:00
Nate EmmertandClaude Sonnet 4.6 ec1e9d3359 Dashboard visual redesign: hero, section cards, sparklines, color tiles, today bar
- Hero section with 5.5rem temperature, feels-like, live wind description
- Humidity, pressure, solar radiation, wind sparklines drawn from history data
- Today at a glance bar: today's high/low temp, rain total, peak gust
- Tile color tinting by value: temp (hot/warm/cool/cold), UV severity, wind, rain rate
- Wind cardinal direction shown in hero subtitle and secondary wind tile
- Chart lines now have subtle gradient area fill (non-dashed series only)
- Chart height increased from 200px to 240px; cards get hover shadow
- Section cards with light headers group conditions, totals, and history

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-20 08:57:29 -04:00
Nate EmmertandClaude Sonnet 4.6 c5cdd39eb3 Add maxdailygust, indoor feelsLike/dewPoint, and Ambient rain accumulators
- Max Gust Today tile (maxdailygust from Ambient)
- Feels Like In tile (feelsLikein, Ambient-computed)
- Use Ambient's dewPointin directly instead of computing from tempinf/humidityin
- Event Rain tile (eventrainin, shows only when > 0)
- Total Rain lifetime tile (totalrainin)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-20 08:50:01 -04:00
Nate EmmertandClaude Sonnet 4.6 a535721bf8 Add NWS alerts, dry/wet streak, and indoor sensor support to dashboard
- NWS active alerts shown as color-coded cards at top of dashboard (5-min cache), auto-refresh every 5 min
- Station location (lat/lon) configurable in settings; falls back to push subscription coordinates
- Consecutive dry/wet streak tile in extended stats (60-day lookback, 0.01" rain threshold)
- Indoor sensor tiles (Temp In, Humidity In, Dew Point In) auto-show when station reports tempinf/humidityin
- Indoor temperature and humidity history charts when indoor data is present in selected range

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-20 08:42:33 -04:00