# 12 - RouteTrack Pi — Mobile UX Upgrade (Shift Controls + Status)

#### **Date:** December 25th, 2025  
**Category:** Raspberry Pi / GPS / Web UI / UX  
**Backlink:** [08 — RouteTrack Pi — Local Dashboard (Leaflet + Flask)](https://docs.natenetworks.com/books/06-raspberry-pi-python-linux-tips/page/08-routetrack-pi-local-web-dashboard-flask-api-leaflet-map)

---

# Project Goal

This update makes the RouteTrack dashboard **easy and safe to use from a phone**, especially since this Pi will be:

- powered down frequently
- used on the go
- accessed quickly before/after driving

The dashboard becomes a **real operator UI**:

- you can glance and instantly know whether a shift is active
- you can start/stop with big buttons (no scrolling)
- the UI recovers cleanly after reboot

---

# What We Added (UX Features)

## 1) Shift Status Badge (Top Bar)

Shows:

- 🟢 **ACTIVE** (with start time)
- 🔴 **STOPPED**

## 2) Sticky Shift Controls (Bottom Bar)

Large buttons designed for mobile thumbs:

- Start Shift (green)
- Stop Shift (red)

## 3) Button Safety Rules

- If shift is ACTIVE → Start disabled
- If shift is STOPPED → Stop disabled

## 4) Inline Toast Messages

Non-blocking confirmations like:

- “Shift started”
- “Shift ended”
- “API not reachable yet” (during boot)

## 5) Auto Refresh After Start/Stop

After changing shift state, the UI automatically refreshes:

- route line
- stops
- daily summary
- shift card

---

# File Updates

## Update `app.py` (Shift endpoints + existing APIs)

## Replace the current `/opt/routetrack/web/app.py` with this full version.

```bash
sudo nano /opt/routetrack/web/app.py

```

Paste:

```python
<span class="token comment">#!/usr/bin/env python3</span>
<span class="token triple-quoted-string string">"""
RouteTrack Local Dashboard (Flask)
----------------------------------

Provides:
- Web UI page (Leaflet map)
- JSON API endpoints (read-only route data):
  - /api/summary/<date>
  - /api/points/<date>
  - /api/stops/<date>

Shift Control Endpoints (write minimal shift state only):
  - GET  /api/shift/active
  - POST /api/shift/start
  - POST /api/shift/stop
  - GET  /api/shift/summary

Notes:
- Route endpoints are READ-ONLY from gps_points/stop_events/daily_summary.
- Shift endpoints write only to the shifts table.
"""</span>

<span class="token keyword">import</span> sqlite3
<span class="token keyword">from</span> datetime <span class="token keyword">import</span> datetime<span class="token punctuation">,</span> timezone
<span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> jsonify<span class="token punctuation">,</span> render_template<span class="token punctuation">,</span> request

DB_PATH <span class="token operator">=</span> <span class="token string">"/opt/routetrack/data/routetrack.sqlite"</span>
app <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">db</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> sqlite3<span class="token punctuation">.</span>connect<span class="token punctuation">(</span>DB_PATH<span class="token punctuation">,</span> timeout<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>row_factory <span class="token operator">=</span> sqlite3<span class="token punctuation">.</span>Row
    <span class="token keyword">return</span> conn

<span class="token keyword">def</span> <span class="token function">utc_now_iso</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># ISO-8601 with Z suffix (matches gps_points ts style)</span>
    <span class="token keyword">return</span> datetime<span class="token punctuation">.</span>now<span class="token punctuation">(</span>timezone<span class="token punctuation">.</span>utc<span class="token punctuation">)</span><span class="token punctuation">.</span>replace<span class="token punctuation">(</span>microsecond<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isoformat<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>replace<span class="token punctuation">(</span><span class="token string">"+00:00"</span><span class="token punctuation">,</span> <span class="token string">"Z"</span><span class="token punctuation">)</span>

<span class="token comment"># -------------------------</span>
<span class="token comment"># UI</span>
<span class="token comment"># -------------------------</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">return</span> render_template<span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">)</span>

<span class="token comment"># -------------------------</span>
<span class="token comment"># Health (optional)</span>
<span class="token comment"># -------------------------</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/health"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_health</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
        conn<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"SELECT 1;"</span><span class="token punctuation">)</span>
        conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">False</span><span class="token punctuation">,</span> <span class="token string">"error"</span><span class="token punctuation">:</span> <span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">500</span>

<span class="token comment"># -------------------------</span>
<span class="token comment"># Route data endpoints</span>
<span class="token comment"># -------------------------</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/summary/<day>"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_summary</span><span class="token punctuation">(</span>day<span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"SELECT * FROM daily_summary WHERE date = ?"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>day<span class="token punctuation">,</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    row <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">if</span> <span class="token keyword">not</span> row<span class="token punctuation">:</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"error"</span><span class="token punctuation">:</span> <span class="token string">"No summary for this date"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">404</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token builtin">dict</span><span class="token punctuation">(</span>row<span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/points/<day>"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_points</span><span class="token punctuation">(</span>day<span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>

    start <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>day<span class="token punctuation">}</span></span><span class="token string">T00:00:00Z"</span></span>
    end <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>day<span class="token punctuation">}</span></span><span class="token string">T23:59:59Z"</span></span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token triple-quoted-string string">"""
        SELECT ts, lat, lon
        FROM gps_points
        WHERE ts >= ? AND ts <= ?
          AND mode = 3
          AND lat IS NOT NULL
          AND lon IS NOT NULL
        ORDER BY ts
    """</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>start<span class="token punctuation">,</span> end<span class="token punctuation">)</span><span class="token punctuation">)</span>

    rows <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchall<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    points <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">[</span>r<span class="token punctuation">[</span><span class="token string">"lat"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> r<span class="token punctuation">[</span><span class="token string">"lon"</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token keyword">for</span> r <span class="token keyword">in</span> rows<span class="token punctuation">]</span>
    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span>points<span class="token punctuation">)</span>

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/stops/<day>"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_stops</span><span class="token punctuation">(</span>day<span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>

    start <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>day<span class="token punctuation">}</span></span><span class="token string">T00:00:00Z"</span></span>
    end <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>day<span class="token punctuation">}</span></span><span class="token string">T23:59:59Z"</span></span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token triple-quoted-string string">"""
        SELECT start_ts, end_ts, duration_seconds, lat, lon
        FROM stop_events
        WHERE start_ts >= ? AND start_ts <= ?
        ORDER BY start_ts
    """</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>start<span class="token punctuation">,</span> end<span class="token punctuation">)</span><span class="token punctuation">)</span>

    rows <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchall<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token builtin">dict</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span> <span class="token keyword">for</span> r <span class="token keyword">in</span> rows<span class="token punctuation">]</span><span class="token punctuation">)</span>

<span class="token comment"># -------------------------</span>
<span class="token comment"># Shift endpoints</span>
<span class="token comment"># -------------------------</span>
<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/shift/active"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_shift_active</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token triple-quoted-string string">"""
        SELECT id, start_ts, end_ts
        FROM shifts
        WHERE end_ts IS NULL
        ORDER BY id DESC
        LIMIT 1
    """</span><span class="token punctuation">)</span>
    row <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">if</span> <span class="token keyword">not</span> row<span class="token punctuation">:</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"active"</span><span class="token punctuation">:</span> <span class="token boolean">False</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token string">"active"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span>
        <span class="token string">"id"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string">"start_ts"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string">"end_ts"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"end_ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/shift/start"</span><span class="token punctuation">,</span> methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"POST"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_shift_start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># If already active, do nothing (idempotent-ish)</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"SELECT id, start_ts FROM shifts WHERE end_ts IS NULL ORDER BY id DESC LIMIT 1;"</span><span class="token punctuation">)</span>
    existing <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> existing<span class="token punctuation">:</span>
        conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span> <span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Shift already active"</span><span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">:</span> existing<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"start_ts"</span><span class="token punctuation">:</span> existing<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

    start_ts <span class="token operator">=</span> utc_now_iso<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"INSERT INTO shifts (start_ts) VALUES (?);"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>start_ts<span class="token punctuation">,</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>commit<span class="token punctuation">(</span><span class="token punctuation">)</span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"SELECT id, start_ts FROM shifts WHERE end_ts IS NULL ORDER BY id DESC LIMIT 1;"</span><span class="token punctuation">)</span>
    row <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span> <span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Shift started"</span><span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"start_ts"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/shift/stop"</span><span class="token punctuation">,</span> methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"POST"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_shift_stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"SELECT id, start_ts FROM shifts WHERE end_ts IS NULL ORDER BY id DESC LIMIT 1;"</span><span class="token punctuation">)</span>
    row <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token keyword">not</span> row<span class="token punctuation">:</span>
        conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">False</span><span class="token punctuation">,</span> <span class="token string">"error"</span><span class="token punctuation">:</span> <span class="token string">"No active shift."</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">400</span>

    end_ts <span class="token operator">=</span> utc_now_iso<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">"UPDATE shifts SET end_ts = ? WHERE id = ?;"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>end_ts<span class="token punctuation">,</span> row<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>commit<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"ok"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span> <span class="token string">"message"</span><span class="token punctuation">:</span> <span class="token string">"Shift ended"</span><span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"start_ts"</span><span class="token punctuation">:</span> row<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"end_ts"</span><span class="token punctuation">:</span> end_ts<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/api/shift/summary"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">api_shift_summary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
    conn <span class="token operator">=</span> db<span class="token punctuation">(</span><span class="token punctuation">)</span>
    cur <span class="token operator">=</span> conn<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>

    cur<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token triple-quoted-string string">"""
        SELECT id, start_ts, end_ts
        FROM shifts
        WHERE end_ts IS NULL
        ORDER BY id DESC
        LIMIT 1
    """</span><span class="token punctuation">)</span>
    shift <span class="token operator">=</span> cur<span class="token punctuation">.</span>fetchone<span class="token punctuation">(</span><span class="token punctuation">)</span>
    conn<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">if</span> <span class="token keyword">not</span> shift<span class="token punctuation">:</span>
        <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"error"</span><span class="token punctuation">:</span> <span class="token string">"No active shift."</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">404</span>

    <span class="token comment"># Simple summary for the UI (elapsed seconds)</span>
    start_dt <span class="token operator">=</span> datetime<span class="token punctuation">.</span>fromisoformat<span class="token punctuation">(</span>shift<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>replace<span class="token punctuation">(</span><span class="token string">"Z"</span><span class="token punctuation">,</span> <span class="token string">"+00:00"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    now_dt <span class="token operator">=</span> datetime<span class="token punctuation">.</span>now<span class="token punctuation">(</span>timezone<span class="token punctuation">.</span>utc<span class="token punctuation">)</span>
    elapsed_s <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span><span class="token punctuation">(</span>now_dt <span class="token operator">-</span> start_dt<span class="token punctuation">)</span><span class="token punctuation">.</span>total_seconds<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token string">"active"</span><span class="token punctuation">:</span> <span class="token boolean">True</span><span class="token punctuation">,</span>
        <span class="token string">"id"</span><span class="token punctuation">:</span> shift<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string">"start_ts"</span><span class="token punctuation">:</span> shift<span class="token punctuation">[</span><span class="token string">"start_ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string">"elapsed_seconds"</span><span class="token punctuation">:</span> elapsed_s
    <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    app<span class="token punctuation">.</span>run<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">"0.0.0.0"</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">5000</span><span class="token punctuation">,</span> debug<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span>

```

Make executable (optional, harmless):

```bash
sudo chmod +x /opt/routetrack/web/app.py

```

Restart dashboard:

```bash
sudo systemctl restart routetrack-dashboard.service

```

Quick verify:

```bash
curl http://localhost:5000/api/shift/active

```

---

## ✅ Update `index.html` (Mobile UI + sticky controls + status)

Edit:

```bash
sudo nano /opt/routetrack/web/templates/index.html

```

Paste the full file:

```html
<span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">doctype</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>RouteTrack Dashboard<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>

  <span class="token comment"><!-- Leaflet (CDN) --></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/leaflet@1.9.4/dist/leaflet.css<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/leaflet@1.9.4/dist/leaflet.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
    <span class="token selector">:root</span> <span class="token punctuation">{</span>
      <span class="token property">--bg</span><span class="token punctuation">:</span> #0f0f0f<span class="token punctuation">;</span>
      <span class="token property">--panel</span><span class="token punctuation">:</span> #151515<span class="token punctuation">;</span>
      <span class="token property">--text</span><span class="token punctuation">:</span> #f2f2f2<span class="token punctuation">;</span>
      <span class="token property">--muted</span><span class="token punctuation">:</span> #bdbdbd<span class="token punctuation">;</span>
      <span class="token property">--ok</span><span class="token punctuation">:</span> #16a34a<span class="token punctuation">;</span>
      <span class="token property">--stop</span><span class="token punctuation">:</span> #dc2626<span class="token punctuation">;</span>
      <span class="token property">--warn</span><span class="token punctuation">:</span> #f59e0b<span class="token punctuation">;</span>
      <span class="token property">--card</span><span class="token punctuation">:</span> #1c1c1c<span class="token punctuation">;</span>
      <span class="token property">--border</span><span class="token punctuation">:</span> #2b2b2b<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">font-family</span><span class="token punctuation">:</span> Arial<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">#topbar</span> <span class="token punctuation">{</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 10px 12px<span class="token punctuation">;</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--panel<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
      <span class="token property">gap</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span>
      <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
      <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span>
      <span class="token property">border-bottom</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">#brand</span> <span class="token punctuation">{</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">#statusBadge</span> <span class="token punctuation">{</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 4px 10px<span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 999px<span class="token punctuation">;</span>
      <span class="token property">font-size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span>
      <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token selector">.badge-active</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>22<span class="token punctuation">,</span>163<span class="token punctuation">,</span>74<span class="token punctuation">,</span>.6<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">.badge-stopped</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>220<span class="token punctuation">,</span>38<span class="token punctuation">,</span>38<span class="token punctuation">,</span>.6<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token selector">#topControls</span> <span class="token punctuation">{</span>
      <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
      <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
      <span class="token property">gap</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
      <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">input[type="date"]</span><span class="token punctuation">{</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 6px 8px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">button</span> <span class="token punctuation">{</span>
      <span class="token property">border</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 9px 12px<span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span>
      <span class="token property">font-weight</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
      <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token selector">button:disabled</span> <span class="token punctuation">{</span> <span class="token property">opacity</span><span class="token punctuation">:</span> 0.45<span class="token punctuation">;</span> <span class="token property">cursor</span><span class="token punctuation">:</span> not-allowed<span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token selector">.btn</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #2a2a2a<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">.btnStart</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--ok<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">.btnStop</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--stop<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token selector">#map</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 62vh<span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token selector">#content</span> <span class="token punctuation">{</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span>
      <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
      <span class="token property">gap</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">.card</span> <span class="token punctuation">{</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">h3</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0 0 8px 0<span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">.row</span> <span class="token punctuation">{</span> <span class="token property">margin</span><span class="token punctuation">:</span> 6px 0<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--muted<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">code</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #232323<span class="token punctuation">;</span> <span class="token property">padding</span><span class="token punctuation">:</span> 2px 6px<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 6px<span class="token punctuation">;</span> <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token comment">/* Sticky bottom control bar for mobile */</span>
    <span class="token selector">#shiftBar</span> <span class="token punctuation">{</span>
      <span class="token property">position</span><span class="token punctuation">:</span> sticky<span class="token punctuation">;</span>
      <span class="token property">bottom</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>15<span class="token punctuation">,</span>15<span class="token punctuation">,</span>15<span class="token punctuation">,</span>.92<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">blur</span><span class="token punctuation">(</span>8px<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">border-top</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 10px 12px<span class="token punctuation">;</span>
      <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
      <span class="token property">gap</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span>
      <span class="token property">z-index</span><span class="token punctuation">:</span> 999<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token selector">#shiftBar button</span> <span class="token punctuation">{</span>
      <span class="token property">flex</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 14px 12px<span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
      <span class="token property">font-size</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/* Toast */</span>
    <span class="token selector">#toast</span> <span class="token punctuation">{</span>
      <span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
      <span class="token property">left</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
      <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>-50%<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">bottom</span><span class="token punctuation">:</span> 86px<span class="token punctuation">;</span>
      <span class="token property">background</span><span class="token punctuation">:</span> #111<span class="token punctuation">;</span>
      <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--border<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">padding</span><span class="token punctuation">:</span> 10px 12px<span class="token punctuation">;</span>
      <span class="token property">border-radius</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span>
      <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
      <span class="token property">z-index</span><span class="token punctuation">:</span> 1000<span class="token punctuation">;</span>
      <span class="token property">max-width</span><span class="token punctuation">:</span> 92vw<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token selector">#toast.ok</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>22<span class="token punctuation">,</span>163<span class="token punctuation">,</span>74<span class="token punctuation">,</span>.7<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">#toast.err</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>220<span class="token punctuation">,</span>38<span class="token punctuation">,</span>38<span class="token punctuation">,</span>.7<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token selector">#toast.warn</span> <span class="token punctuation">{</span> <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>245<span class="token punctuation">,</span>158<span class="token punctuation">,</span>11<span class="token punctuation">,</span>.7<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

    <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 900px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
      <span class="token selector">#map</span> <span class="token punctuation">{</span> <span class="token property">height</span><span class="token punctuation">:</span> 70vh<span class="token punctuation">;</span> <span class="token punctuation">}</span>
      <span class="token selector">#shiftBar</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 520px<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 0 auto 12px auto<span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>topbar<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>brand<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>RouteTrack<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>statusBadge<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>badge-stopped<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>🔴 SHIFT STOPPED<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>topControls<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--muted<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>Date<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>day<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>date<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>loadAll()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Reload<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>map<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h3</span><span class="token punctuation">></span></span>Active Shift<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h3</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>shiftCard<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Checking shift status…<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h3</span><span class="token punctuation">></span></span>Daily Summary<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h3</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summary<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Loading…<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h3</span><span class="token punctuation">></span></span>Stops<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h3</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stops<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Loading…<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

  <span class="token comment"><!-- Sticky mobile shift controls --></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>shiftBar<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btnStart<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btnStart<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>startShift()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Start Shift<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btnStop<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btnStop<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stopShift()<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Stop Shift<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>toast<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span>
  // Default date = today (browser local time)
  const dayInput = document.getElementById("day");
  dayInput.valueAsDate = new Date();

  const statusBadge = document.getElementById("statusBadge");
  const btnStart = document.getElementById("btnStart");
  const btnStop = document.getElementById("btnStop");
  const toastEl = document.getElementById("toast");

  const map = L.map("map").setView([38.7153, -89.94], 13);
  L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
    maxZoom: 19,
    attribution: "<span class="token entity named-entity" title="©">&copy;</span> OpenStreetMap contributors"
  }).addTo(map);

  let routeLine = null;
  let stopMarkers = [];

  function toast(msg, type="ok") {
    toastEl.className = "";
    toastEl.classList.add(type);
    toastEl.textContent = msg;
    toastEl.style.display = "block";
    setTimeout(() => toastEl.style.display = "none", 3200);
  }

  function setShiftUI(active, start_ts=null) {
    if (active) {
      statusBadge.textContent = `🟢 SHIFT ACTIVE${start_ts ? " — " + start_ts : ""}`;
      statusBadge.classList.remove("badge-stopped");
      statusBadge.classList.add("badge-active");
      btnStart.disabled = true;
      btnStop.disabled = false;
    } else {
      statusBadge.textContent = "🔴 SHIFT STOPPED";
      statusBadge.classList.remove("badge-active");
      statusBadge.classList.add("badge-stopped");
      btnStart.disabled = false;
      btnStop.disabled = true;
    }
  }

  async function apiJSON(url, opts={}) {
    const res = await fetch(url, opts);
    let data = {};
    try { data = await res.json(); } catch(e) {}
    return { res, data };
  }

  async function refreshShiftState() {
    const { res, data } = await apiJSON("/api/shift/active");
    if (!res.ok) {
      setShiftUI(false);
      document.getElementById("shiftCard").textContent = "Shift API not reachable yet.";
      return;
    }

    setShiftUI(!!data.active, data.start_ts || null);

    if (data.active) {
      // Show elapsed time quickly
      const { data: sum } = await apiJSON("/api/shift/summary");
      if (!sum || sum.error) {
        document.getElementById("shiftCard").innerHTML =
          `<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Active shift detected. Start: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${data.start_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>`;
        return;
      }
      const mins = Math.floor((sum.elapsed_seconds || 0) / 60);
      document.getElementById("shiftCard").innerHTML =
        `<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Started: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${sum.start_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Elapsed: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>${mins}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> min<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>`;
    } else {
      document.getElementById("shiftCard").textContent = "No active shift.";
    }
  }

  async function startShift() {
    btnStart.disabled = true;
    const { res, data } = await apiJSON("/api/shift/start", { method: "POST" });
    if (!res.ok || data.ok === false) {
      toast(data.error || "Failed to start shift.", "err");
      await refreshShiftState();
      return;
    }
    toast(data.message || "Shift started.", "ok");
    await refreshShiftState();
    await loadAll(); // refresh route/stops/summary
  }

  async function stopShift() {
    // One simple safety check (no popup spam):
    if (!confirm("End shift now?")) return;

    btnStop.disabled = true;
    const { res, data } = await apiJSON("/api/shift/stop", { method: "POST" });
    if (!res.ok || data.ok === false) {
      toast(data.error || "Failed to stop shift.", "err");
      await refreshShiftState();
      return;
    }
    toast(data.message || "Shift ended.", "ok");
    await refreshShiftState();
    await loadAll();
  }

  async function loadAll() {
    const day = dayInput.value;
    await loadRoute(day);
    await loadStops(day);
    await loadSummary(day);
  }

  async function loadRoute(day) {
    const { res, data } = await apiJSON(`/api/points/${day}`);
    const pts = Array.isArray(data) ? data : [];

    if (routeLine) map.removeLayer(routeLine);
    if (!pts.length) return;

    routeLine = L.polyline(pts, { weight: 4 }).addTo(map);
    map.fitBounds(routeLine.getBounds());
  }

  async function loadStops(day) {
    stopMarkers.forEach(m => map.removeLayer(m));
    stopMarkers = [];

    const { data } = await apiJSON(`/api/stops/${day}`);
    const stops = Array.isArray(data) ? data : [];

    const stopsDiv = document.getElementById("stops");
    stopsDiv.innerHTML = "";

    if (!stops.length) {
      stopsDiv.innerHTML = "<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>row<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>No stops found.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>";
      return;
    }

    stops.forEach(s => {
      const durMin = Math.round((s.duration_seconds || 0) / 60);
      stopsDiv.innerHTML += `<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        Stop: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${s.start_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span> → <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${s.end_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span>
        (${durMin} min)
      <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>`;

      if (s.lat && s.lon) {
        const m = L.marker([s.lat, s.lon]).addTo(map)
          .bindPopup(`Stop (${durMin} min)<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span>${s.start_ts}`);
        stopMarkers.push(m);
      }
    });
  }

  async function loadSummary(day) {
    const summaryDiv = document.getElementById("summary");
    summaryDiv.innerHTML = "";

    const { data } = await apiJSON(`/api/summary/${day}`);

    if (!data || data.error) {
      summaryDiv.innerHTML = `<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>No summary for ${day}. Run processor first.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>`;
      return;
    }

    summaryDiv.innerHTML = `
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Start: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${data.start_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>End: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>${data.end_ts}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Distance: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>${data.total_distance_miles}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> miles<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Moving: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>${Math.round(data.moving_time_seconds/60)}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> minutes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Stopped: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>${Math.round(data.stopped_time_seconds/60)}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> minutes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Stops: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>${data.stop_count}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
    `;
  }

  // Boot behavior: shift state first, then route data
  (async () => {
    try {
      await refreshShiftState();
      await loadAll();
    } catch (e) {
      toast("Dashboard loading… waiting on services.", "warn");
    }

    // Light auto-refresh of shift status every 15s
    setInterval(refreshShiftState, 15000);
  })();
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>

```

Restart dashboard:

```bash
sudo systemctl restart routetrack-dashboard.service

```

---

# Verification

## Confirm shift API works

```bash
curl http://localhost:5000/api/shift/active

```

Start shift:

```bash
curl -X POST http://localhost:5000/api/shift/start

```

Stop shift:

```bash
curl -X POST http://localhost:5000/api/shift/stop

```

Then load the dashboard from your phone and confirm:

- status badge flips correctly
- buttons enable/disable properly
- map + stats refresh after shift actions

---

# Why This UX Matters (for a portable device)

This dashboard is now resilient for:

- frequent power-off/on cycles
- quick “start shift / drive / stop shift” workflows
- using the UI one-handed on a phone

It reduces mistakes and removes uncertainty — which is exactly what you want when this becomes a daily tool.

---

## Next Steps

1. Add **“Shift view” mode** (show only points within the active shift window)
2. Add **start/stop shift button inside the map** (floating control)
3. Improve stop detection with:
    
    
    - ignition off detection (optional)
    - drift suppression using epx/epy thresholds