<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
  <meta name="theme-color" content="#eef3f1">
  <title>Traffic Lab | Passage Tool</title>
  <link rel="icon" href="./favicon.svg" type="image/svg+xml">
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
  <script>
    (() => {
      const theme = localStorage.getItem("passagetool-traffic-lab-theme") || "dark";
      document.documentElement.dataset.theme = theme === "light" ? "light" : "dark";
    })();
  </script>
  <link rel="stylesheet" href="./css/traffic-lab.css?v=20260725-google-map">
</head>
<body>
  <main class="lab-shell">
    <header class="lab-header">
      <div class="brand-row">
        <img src="./favicon.svg" width="42" height="42" alt="">
        <div>
          <p class="eyebrow">Passage Tool</p>
          <h1>Passage Traffic</h1>
        </div>
      </div>
    </header>

    <nav class="view-tabs" aria-label="Traffic Lab views">
      <button id="passageTab" class="tab-button active" type="button" data-view="passage" aria-controls="passageView" aria-selected="true">Passage</button>
      <button id="mapTab" class="tab-button" type="button" data-view="map" aria-controls="trafficMapView" aria-selected="false">Traffic map</button>
      <button id="diagnosticsTab" class="tab-button" type="button" data-view="diagnostics" aria-controls="diagnosticsView" aria-selected="false">Diagnostics</button>
    </nav>

    <section id="passageView" class="view-pane passage-view" aria-label="Passage traffic">
      <section class="route-picker-panel" aria-label="Passage controls">
        <label>
          <span>From</span>
          <select id="routeFromSelect">
            <option value="basel">Basel</option>
            <option value="breisach">Breisach</option>
            <option value="kehl">Kehl</option>
            <option value="iffezheim" selected>Iffezheim</option>
          </select>
        </label>
        <label>
          <span>To</span>
          <select id="routeToSelect">
            <option value="basel" selected>Basel</option>
            <option value="breisach">Breisach</option>
            <option value="kehl">Kehl</option>
            <option value="iffezheim">Iffezheim</option>
          </select>
        </label>
        <label>
          <span>Departure</span>
          <input id="departureInput" type="text" value="Now" readonly>
        </label>
        <label>
          <span>Mode</span>
          <select id="themeSelect">
            <option value="dark">Dark</option>
            <option value="light">Light</option>
          </select>
        </label>
        <button id="reverseDirectionBtn" class="btn secondary" type="button">Reverse direction</button>
        <button id="passageRefreshBtn" class="btn primary" type="button">Refresh</button>
      </section>

      <section class="passage-result-card">
        <div class="section-title">
          <div>
            <p class="eyebrow">Passage traffic</p>
            <h2 id="passageRouteTitle">Iffezheim -> Basel</h2>
          </div>
          <p id="passageUpdatedText">Updated: --</p>
        </div>
        <div class="passage-result-grid">
          <div class="passage-primary-result">
            <span>Estimated passage</span>
            <strong id="estimatedPassageMetric">Unavailable</strong>
            <small id="estimatedPassageText">Historical model is collecting data</small>
          </div>
          <div class="passage-result-side">
            <article>
              <span>Expected arrival</span>
              <strong id="expectedArrivalMetric">--</strong>
            </article>
            <article>
              <span>Traffic delay</span>
              <strong id="trafficDelayMetric">Not calibrated</strong>
            </article>
            <article>
              <span>Range</span>
              <strong id="passageRangeMetric">Unavailable</strong>
            </article>
            <article>
              <span>Confidence</span>
              <strong id="confidenceMetric">--</strong>
            </article>
          </div>
        </div>
        <div class="time-breakdown">
          <div><span>Base sailing time</span><strong id="baseSailingTimeText">Collecting historical passages</strong></div>
          <div><span>Normal lock operations</span><strong id="normalLockTimeText">Collecting lock events</strong></div>
          <div><span>Detected queue delays</span><strong id="queueDelayText">Counts available, model not calibrated</strong></div>
          <div><span>Final estimate</span><strong id="finalEstimateText">Unavailable until enough samples exist</strong></div>
        </div>
      </section>

      <section class="route-status-panel" aria-label="Route status">
        <div class="section-title">
          <h2 id="routeStatusMetric">Route status: --</h2>
          <p id="routeStatusText">Waiting for data</p>
        </div>
      </section>

      <section class="passage-route-panel traffic-adjusted-panel" aria-label="Traffic adjusted section estimates">
        <div class="section-title">
          <div>
            <p class="eyebrow">Traffic-adjusted ETA</p>
            <h2>Section estimates now</h2>
          </div>
          <p id="sectionEstimateSummaryText">Waiting for observed traffic model</p>
        </div>
        <div class="table-scroll">
          <table class="section-estimate-table">
            <thead>
              <tr>
              <th>Section</th>
              <th>Basis</th>
              <th>Traffic now</th>
              <th>Chambers</th>
              <th>Traffic add</th>
              <th>Estimated now</th>
              <th>Range</th>
              <th>Confidence</th>
              </tr>
            </thead>
            <tbody id="sectionEstimateRows">
              <tr><td colspan="8" class="muted">No model rows yet</td></tr>
            </tbody>
          </table>
        </div>
      </section>

      <section class="captain-kpi-grid" aria-label="Key route data">
        <article class="captain-kpi">
          <span>Vessels ahead</span>
          <strong id="vesselsAheadMetric">--</strong>
          <small id="vesselsAheadText">selected direction only</small>
        </article>
        <article class="captain-kpi">
          <span>Currently waiting</span>
          <strong id="currentlyWaitingMetric">--</strong>
          <small>detected at route locks</small>
        </article>
        <article class="captain-kpi">
          <span>Locks with delay</span>
          <strong id="locksWithDelayMetric">--</strong>
          <small>queue candidates</small>
        </article>
        <article class="captain-kpi">
          <span>Data updated</span>
          <strong id="dataUpdatedMetric">--</strong>
          <small id="unknownDirectionText">-- unknown direction</small>
        </article>
      </section>

      <section class="direction-summary-panel" aria-label="Traffic directions">
        <article>
          <span id="selectedDirectionLabel">Towards Breisach</span>
          <strong id="selectedDirectionMetric">--</strong>
          <small>used in route calculation</small>
        </article>
        <article>
          <span>Opposite direction</span>
          <strong id="oppositeDirectionMetric">--</strong>
          <small>not counted as vessels ahead</small>
        </article>
      </section>

      <section class="passage-route-panel" aria-label="Route axis">
        <div class="section-title">
          <h2>Route axis</h2>
          <p id="routeAxisSummaryText">Locks in passing order</p>
        </div>
        <div id="routeAxisRows" class="route-axis-list"></div>
      </section>

      <section class="passage-route-panel" aria-label="Locks on route">
        <div class="section-title">
          <h2>Locks on route</h2>
          <p id="lockListSummaryText">Delay estimates are not calibrated yet</p>
        </div>
        <div id="passageLockCards" class="passage-lock-list"></div>
      </section>

      <section class="passage-route-panel compact-info" aria-label="Confidence and cargo">
        <details class="confidence-details" open>
          <summary>Why this confidence?</summary>
          <ul id="confidenceReasonList"></ul>
        </details>
        <article class="dangerous-cargo-card">
          <h2>Dangerous cargo on route</h2>
          <div class="cargo-grid">
            <div><span>Confirmed</span><strong id="cargoConfirmedMetric">--</strong></div>
            <div><span>Confirmed none</span><strong id="cargoNoneMetric">--</strong></div>
            <div><span>Unknown</span><strong id="cargoUnknownMetric">--</strong></div>
          </div>
        </article>
      </section>
    </section>

    <section id="trafficMapView" class="view-pane map-view" aria-label="Traffic map" hidden>
      <section class="route-picker-panel map-picker-panel" aria-label="Traffic map controls">
        <label>
          <span>From</span>
          <select id="mapRouteFromSelect">
            <option value="basel">Basel</option>
            <option value="breisach">Breisach</option>
            <option value="kehl">Kehl</option>
            <option value="iffezheim" selected>Iffezheim</option>
          </select>
        </label>
        <label>
          <span>To</span>
          <select id="mapRouteToSelect">
            <option value="basel" selected>Basel</option>
            <option value="breisach">Breisach</option>
            <option value="kehl">Kehl</option>
            <option value="iffezheim">Iffezheim</option>
          </select>
        </label>
        <label class="map-key-field">
          <span>Google Maps key</span>
          <input id="googleMapsKeyInput" type="password" autocomplete="off" spellcheck="false" placeholder="Optional">
        </label>
        <button id="mapReverseDirectionBtn" class="btn secondary" type="button">Reverse direction</button>
        <button id="mapRefreshBtn" class="btn primary" type="button">Refresh</button>
      </section>

      <section class="map-shell-panel google-map-panel" aria-label="Traffic map view">
        <div class="section-title">
          <div>
            <p class="eyebrow">Traffic map overlay</p>
            <h2 id="mapRouteTitle">Iffezheim -> Basel</h2>
          </div>
          <p id="mapUpdatedText">Updated: --</p>
        </div>
        <div class="traffic-map-layout">
          <div id="trafficMap" class="traffic-map"></div>
          <div class="map-dashboard-grid" aria-label="Traffic summary">
            <article class="map-kpi">
              <span>Route traffic</span>
              <strong id="mapTrafficMetric">--</strong>
              <small id="mapTrafficText">Waiting for traffic data</small>
            </article>
            <article class="map-kpi">
              <span>Max lock delay</span>
              <strong id="mapMaxDelayMetric">--</strong>
              <small id="mapMaxDelayText">current lock candidates</small>
            </article>
            <article class="map-kpi">
              <span>Waiting now</span>
              <strong id="mapWaitingMetric">--</strong>
              <small id="mapWaitingText">detected near locks</small>
            </article>
            <article class="map-kpi">
              <span>Vessels shown</span>
              <strong id="mapVesselsMetric">--</strong>
              <small id="mapVesselsText">selected route corridor</small>
            </article>
          </div>
          <aside class="map-side-panel" aria-label="Traffic map details">
            <div class="map-legend" aria-label="Traffic legend">
              <span><i class="legend-line clear"></i>Clear</span>
              <span><i class="legend-line slow"></i>Busy</span>
              <span><i class="legend-line heavy"></i>Queue</span>
              <span><i class="legend-line blocked"></i>Blocked</span>
            </div>
            <div>
              <h3>Locks with delay</h3>
              <div id="mapIncidentList" class="map-incident-list">
                <p class="muted">No map data yet</p>
              </div>
            </div>
          </aside>
        </div>
      </section>
    </section>

    <div id="diagnosticsView" class="view-pane technical-view" role="tabpanel" aria-label="Diagnostics" hidden>
    <section class="control-panel" aria-label="Traffic Lab controls">
      <label>
        <span>API</span>
        <input id="apiBaseInput" type="url" autocomplete="off" spellcheck="false">
      </label>
      <label>
        <span>Lab key</span>
        <input id="apiKeyInput" type="password" autocomplete="off" spellcheck="false" placeholder="Paste lab key">
      </label>
      <button id="refreshBtn" class="btn primary" type="button">Refresh</button>
      <button id="collectBtn" class="btn secondary" type="button">Collect now</button>
      <button id="exportPassagesBtn" class="btn secondary" type="button">Download passages .txt</button>
    </section>

    <section class="status-bar" aria-live="polite">
      <span id="sourceStatus" class="status-pill">Checking</span>
      <span id="lastRunText">Last run: --</span>
      <span id="sourceUrlText">Source: --</span>
    </section>

    <section class="metric-grid" aria-label="Traffic summary">
      <article class="metric-tile">
        <span>Received</span>
        <strong id="receivedMetric">--</strong>
        <small id="savedMetric">Saved --</small>
      </article>
      <article class="metric-tile">
        <span>Upstream</span>
        <strong id="towardsBaselMetric">--</strong>
        <small>towards Basel</small>
      </article>
      <article class="metric-tile">
        <span>Downstream</span>
        <strong id="towardsBreisachMetric">--</strong>
        <small>towards Iffezheim</small>
      </article>
      <article class="metric-tile">
        <span>Waiting / at locks</span>
        <strong id="unknownDirectionMetric">--</strong>
        <small>stopped near or inside locks</small>
      </article>
    </section>

    <section class="quality-panel" aria-label="AIS verification">
      <div class="section-title">
        <h2>AIS check</h2>
        <p id="qualitySummaryText">Active window: --</p>
      </div>
      <div class="quality-grid">
        <article class="quality-item">
          <span>Active targets</span>
          <strong id="activeTargetsMetric">--</strong>
          <small>all active AIS targets</small>
        </article>
        <article class="quality-item">
          <span>Route km matched</span>
          <strong id="routeKmKnownMetric">--</strong>
          <small id="routeKmKnownText">--</small>
        </article>
        <article class="quality-item">
          <span>Shown in panel</span>
          <strong id="directionKnownMetric">--</strong>
          <small id="directionKnownText">--</small>
        </article>
        <article class="quality-item">
          <span>Lock-related</span>
          <strong id="lockAreaMetric">--</strong>
          <small>Kembs to Iffezheim</small>
        </article>
      </div>
    </section>

    <section class="quality-panel" aria-label="Collector diagnostics">
      <div class="section-title">
        <h2>Collector diagnostics</h2>
        <p id="diagnosticsSummaryText">Checking collector</p>
      </div>
      <div class="quality-grid diagnostics-grid">
        <article class="quality-item">
          <span>Last success</span>
          <strong id="diagLastSuccessMetric">--</strong>
          <small id="diagLastSuccessText">--</small>
        </article>
        <article class="quality-item">
          <span>Runs 24h</span>
          <strong id="diagRunsMetric">--</strong>
          <small id="diagErrorsText">-- errors</small>
        </article>
        <article class="quality-item">
          <span>Last run vessels</span>
          <strong id="diagReceivedMetric">--</strong>
          <small id="diagSavedText">saved --</small>
        </article>
        <article class="quality-item">
          <span>Unchanged</span>
          <strong id="diagUnchangedMetric">--</strong>
          <small>presence still counted</small>
        </article>
        <article class="quality-item">
          <span>Stored 24h</span>
          <strong id="diagPositionsMetric">--</strong>
          <small id="diagDistinctText">-- vessels</small>
        </article>
        <article class="quality-item">
          <span>Newest EuRIS age</span>
          <strong id="diagNewestAgeMetric">--</strong>
          <small id="diagNewestTimestampText">--</small>
        </article>
        <article class="quality-item">
          <span>Missing ID/position</span>
          <strong id="diagMissingCoreMetric">--</strong>
          <small>latest collection</small>
        </article>
        <article class="quality-item">
          <span>Missing SOG/COG</span>
          <strong id="diagMissingMotionMetric">--</strong>
          <small>latest collection</small>
        </article>
      </div>
    </section>

    <section class="route-panel" aria-label="Route traffic overview">
      <div class="section-title">
        <h2>Basel - Iffezheim traffic</h2>
        <p id="routeSummaryText">--</p>
      </div>
      <div class="table-scroll">
        <table class="section-table">
          <thead>
            <tr>
              <th>#</th>
              <th>Section / lock</th>
              <th>Type</th>
              <th>Upstream</th>
              <th>Downstream</th>
              <th>Waiting/no dir</th>
              <th>Total</th>
            </tr>
          </thead>
          <tbody id="sectionRows"></tbody>
        </table>
      </div>
    </section>

    <section class="observed-panel" aria-label="Traffic based transit basis">
      <div class="section-title">
        <h2>Traffic-based transit basis</h2>
        <p id="observedSummaryText">Checking AIS traffic pressure</p>
      </div>
      <div class="observed-grid">
        <div class="observed-table">
          <h3>Route sections</h3>
          <div class="table-scroll">
            <table>
              <thead>
                <tr>
                  <th>Section</th>
                  <th>Upstream traffic</th>
                  <th>Downstream traffic</th>
                  <th>Waiting/no dir</th>
                  <th>Active</th>
                  <th>Status</th>
                </tr>
              </thead>
              <tbody id="observedSectionRows"></tbody>
            </table>
          </div>
        </div>
        <div class="observed-table">
          <h3>Lock traffic pressure</h3>
          <div class="table-scroll">
            <table>
              <thead>
                <tr>
                  <th>Lock</th>
                  <th>Upstream traffic</th>
                  <th>Downstream traffic</th>
                  <th>Waiting/no dir</th>
                  <th>Active</th>
                  <th>Status</th>
                </tr>
              </thead>
              <tbody id="observedLockRows"></tbody>
            </table>
          </div>
        </div>
        <div class="observed-table">
          <h3>Completed section passages</h3>
          <div class="table-scroll">
            <table>
              <thead>
                <tr>
                  <th>Section</th>
                  <th>Target</th>
                  <th>Direction</th>
                  <th>Start traffic</th>
                  <th>End traffic</th>
                  <th>Started</th>
                  <th>Ended</th>
                  <th>Duration</th>
                </tr>
              </thead>
              <tbody id="completedPassageRows"></tbody>
            </table>
          </div>
        </div>
      </div>
    </section>

    <section class="lock-grid" aria-label="Lock diagnostics">
      <div class="section-title full">
        <h2>Lock diagnostics</h2>
        <p>Diagnostic candidates only</p>
      </div>
      <div id="lockCards" class="lock-cards"></div>
    </section>

    <section class="table-panel" aria-label="Latest vessels">
      <div class="section-title">
        <h2>Shown vessels</h2>
        <p id="vesselCountText">--</p>
      </div>
      <div class="table-scroll">
        <table>
          <thead>
            <tr>
              <th>Vessel</th>
              <th>Last seen</th>
              <th>Route km</th>
              <th>Direction</th>
              <th>State</th>
              <th>Lock</th>
              <th>SOG</th>
              <th>Danger</th>
            </tr>
          </thead>
          <tbody id="vesselRows"></tbody>
        </table>
      </div>
    </section>

    <section class="table-panel" aria-label="Vessel inspector">
      <div class="section-title">
        <h2>Vessel inspector</h2>
        <p id="inspectorSummaryText">Select a target</p>
      </div>
      <div class="inspector-toolbar">
        <label>
          <span>Target</span>
          <select id="vesselSelect"></select>
        </label>
      </div>
      <div class="quality-grid inspector-grid">
        <article class="quality-item">
          <span>Target</span>
          <strong id="inspectorTargetMetric">--</strong>
          <small>masked hash</small>
        </article>
        <article class="quality-item">
          <span>First seen</span>
          <strong id="inspectorFirstSeenMetric">--</strong>
          <small id="inspectorLastSeenText">last --</small>
        </article>
        <article class="quality-item">
          <span>Samples</span>
          <strong id="inspectorSamplesMetric">--</strong>
          <small id="inspectorCollectedText">collected --</small>
        </article>
        <article class="quality-item">
          <span>SOG / COG</span>
          <strong id="inspectorMotionMetric">--</strong>
          <small id="inspectorSourceText">source --</small>
        </article>
      </div>
      <div class="observed-grid">
        <div class="observed-table">
          <h3>Last 10 positions</h3>
          <div class="table-scroll">
            <table>
              <thead>
                <tr>
                  <th>Collected</th>
                  <th>Source time</th>
                  <th>Route km</th>
                  <th>Lat/lon</th>
                  <th>SOG</th>
                  <th>COG</th>
                  <th>Payload</th>
                </tr>
              </thead>
              <tbody id="inspectorPositionRows"></tbody>
            </table>
          </div>
        </div>
        <div class="observed-table">
          <h3>Raw payload fields</h3>
          <p id="inspectorRawFieldsText" class="raw-fields muted">--</p>
        </div>
      </div>
    </section>

    <section class="history-panel" aria-label="Traffic history">
      <div class="section-title">
        <h2>History</h2>
        <p id="historySummaryText">--</p>
      </div>
      <div class="table-scroll">
        <table class="history-table">
          <thead>
            <tr>
              <th>Collected</th>
              <th>Received</th>
              <th>Saved</th>
              <th>Corridor</th>
              <th>Km matched</th>
              <th>Direction known</th>
              <th>Shown</th>
              <th>At locks</th>
            </tr>
          </thead>
          <tbody id="historyRows"></tbody>
        </table>
      </div>
    </section>

    <section class="event-panel" aria-label="Event log">
      <div class="section-title">
        <h2>Log</h2>
        <p id="logCountText">0 events</p>
      </div>
      <ol id="eventLog" class="event-log"></ol>
    </section>
    </div>
  </main>
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
  <script src="./js/traffic-lab.js?v=20260725-google-map"></script>
</body>
</html>
