@sailingrotevista/rotevista-dash 7.0.45 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @sailingrotevista/rotevista-dash might be problematic. Click here for more details.

package/README.md CHANGED
@@ -1,90 +1,48 @@
1
- # @sailingrotevista/rotevista-dash
1
+ # Sailing Dashboard Pro (React + TypeScript)
2
2
 
3
- ## Sailing Dashboard Pro (v6.0)
4
-
5
- A tactical marine dashboard and advanced monitoring system for sailboats, designed to run as a Web App (PWA) fully integrated into the **Signal K** ecosystem. Specifically optimized for precision rendering on boat tablets (such as iPads and Samsung Galaxy Tab Active) and built to run efficiently on low-resource gateways like the **Victron Cerbo GX** (running Venus OS Large) or Raspberry Pi.
3
+ A tactical marine dashboard and advanced monitoring system for sailboats, built with React, TypeScript, and Vite. Designed to run seamlessly as a Progressive Web App (PWA) with Signal K integration, optimized for precision rendering on boat tablets (such as iPads and rugged Android tablets) and running on onboard systems (Victron Cerbo GX, Venus OS, or Raspberry Pi).
6
4
 
7
5
  ---
8
6
 
9
7
  ## Core Features
10
8
 
11
- ### 📈 Server-Side RAM-Buffered History
12
- Unlike traditional dashboards that store history in the volatile memory of the client browser (wiping it whenever the screen locks or the browser reloads), this dashboard performs continuous background logging in RAM directly within the Signal K server process. Upon startup, the client instantly loads up to 60 minutes of pre-populated history via a fast JSON API endpoint, ensuring fully drawn, stable charts from the very first second the page is opened.
13
-
14
- ### 🔋 Extreme Low-Power Architecture (Battery Saver)
15
- Engineered for long-range cruising without overheating your mobile devices or draining the boat's house batteries:
16
- * **Event-Driven SVG Redraw:** Complex SVG chart elements are not redrawn on a blind timer. Instead, they are redrawn *only* when a new historical data point is appended to the buffer (reducing the browser's active SVG layout and paint cycles by **93%**).
17
- * **Virtual-DOM Text Protection (`safeSetText`):** Digital text readouts are updated only if their numerical value has actually changed since the previous second, bypassing expensive browser style and layout calculations (*reflow/repaint*).
18
- * **Zero-Overhead Analog Needles:** Pointers (AWA, TWA, Leeway) snap instantly to their new positions at 1Hz instead of forcing continuous 60fps style interpolations, allowing the tablet's GPU to rest in a low-power idle state.
19
-
20
- ### 🧭 Weather Compass & True Wind Direction (TWD) Trends
21
- * **Tactical Trend (Short-term):** Instantly detects lift or header shifts by comparing the 2-second moving average of True Wind Angle (TWA) with the 10-second average.
22
- * **Strategic Trend (Long-term):** Flashing green (CW) and red (CCW) dots on the TWD mini-compass indicate meteorological wind rotations, comparing the last 1 minute of wind with a stable strategic baseline of **15 minutes** under sail or **60 minutes** at anchor.
23
- * **Absolute UTC Epoch Snapping:** Time windows on both the server and any connected clients are locked to absolute UTC second boundaries (00, 10, 20, 30, 40, 50). This eliminates phase offsets and ensures identical tactical trends across all devices on the boat.
24
-
25
- ### 🛡️ Shallow Water Alarms & Geometric Safety Lines
26
- * Automatically draws high-visibility dashed safety lines across the depth chart background to indicate **Warning (Yellow, e.g. 3.5m)** and **Danger (Red, e.g. 2.5m)** thresholds.
27
- * **Non-Scaling Vector Effects:** By using `vector-effect="non-scaling-stroke"`, these lines and the active depth curve remain perfectly sharp, thin, and professional regardless of whether the widget is small or zoomed to full screen.
28
- * **Adaptive 0-Baseline:** In shallow water, the chart minimum is locked to 0 for keel safety; in deep water, the scale floats freely (e.g., 98m to 102m) to reveal the fine contour details of the seabed.
29
-
30
- ### 🔌 Smart Source Locking (Zero-Config)
31
- An intelligent background algorithm assigns priority scores to active hardware sources on your boat (e.g. Yacht Devices N2K GPS vs a generic USB GPS) and locks onto the highest-quality sensor, switching to a backup only if a signal dropout occurs.
32
-
33
- ### ⏰ Sleep & Power-Save Watchdog
34
- Detects when the tablet is unlocked or the browser wakes up a tab from *Power Save* mode, automatically closing orphaned WebSockets, reconnecting, and downloading the latest server-logged history in milliseconds to resume fluid, gap-free operation.
9
+ ### 📈 Real-Time & Historical Sparklines
10
+ - **Adaptive Scales:** Automatic standard or Hercules zoom mode with snap-to-grid resolution.
11
+ - **Dynamic Reef & Danger Thresholds:** Visual warnings (Orange 1st Reef, Red 2nd Reef, Purple storm) and customizable depth safety lines with acoustic alerts.
12
+ - **Elastic History Gap Handling:** Smooth data rendering without synthetic gaps.
35
13
 
36
- ### 🎮 Smart Local Development Auto-Detection
37
- The dashboard automatically detects if it is running locally on your Mac/PC via the `file://` protocol or on `localhost`. In this mode, it still connects to your boat's Cerbo GX over Wi-Fi to stream real-time data, but **bypasses the server's configuration, preserving your local `CONFIG` edits** so you can test scales, alarms, and steps instantly.
14
+ ### 🧭 Dual Central Instruments: Analog Gauge & Weather Radar
15
+ - **Analog Wind Gauge:** Real-time Apparent Wind Angle (AWA), True Wind Angle (TWA), Apparent Wind Speed (AWS), Leeway angle, and Ground Track vector.
16
+ - **Tactical & Gybe Alarms:** Visual and acoustic alarms for deep downwind gybe danger with hysteresis anti-chatter state machine.
17
+ - **Historical Weather Radar:** 8-ring historical true wind direction (TWD) and true wind speed (TWS) radar with Open-Meteo future forecast interpolation and live boat heading alignment.
18
+ - **Quick Switch:** 1-second hold on the TWD mini-compass switches to the historical radar; click anywhere on the radar to return to the analog gauge.
38
19
 
39
- ---
40
-
41
- ## System Requirements
20
+ ### 🌙 Night Mode & Tactical Focus Mode
21
+ - **Tactical Red Night Mode:** 1-second press on the central hotspot toggles full tactical red night mode to preserve night vision.
22
+ - **Fullscreen Mode:** Tap the central hotspot to toggle browser fullscreen.
23
+ - **Tactical Focus Mode:** 1-second press on any data box expands that instrument into high-visibility split-screen mode.
42
24
 
43
- * **Server:** Signal K Node Server (v1.20.0 or higher) installed on a Victron Cerbo GX, Raspberry Pi, or onboard PC.
44
- * **Client:** Any modern PWA-compliant browser supporting ES6 (Safari on iPadOS/iOS, Samsung Internet, Chrome on Android, Chrome/Safari on macOS/Windows).
25
+ ### 📡 Signal K & Simulation Engine
26
+ - Automatically connects to Signal K WebSocket (`ws://${host}/signalk/v1/stream`) when running aboard.
27
+ - Automatically falls back to an integrated dynamic simulation engine when running standalone or in browser previews, keeping all instruments, graphs, and tactical trends active.
45
28
 
46
29
  ---
47
30
 
48
- ## Signal K Data Requirements
49
-
50
- ### Required Foundational Paths
51
- To derive, calculate, and display the entire suite of tactical data, the dashboard must receive the following raw paths from your boat's NMEA network:
31
+ ## Development
52
32
 
53
- * `navigation.speedThroughWater` (STW - Speed through water)
54
- * `navigation.speedOverGround` (SOG - Speed over ground)
55
- * `navigation.courseOverGroundTrue` (COG - Course over ground)
56
- * `navigation.headingTrue` (True Heading - *If missing, the system automatically falls back to Magnetic Heading*)
57
- * `environment.wind.speedApparent` (AWS - Apparent wind speed)
58
- * `environment.wind.angleApparent` (AWA - Apparent wind angle)
59
- * `environment.depth.belowTransducer` (Depth below keel/transducer)
60
- * `navigation.position` (GPS Latitude and Longitude - used for hemisphere detection and CSV logging)
33
+ ```bash
34
+ # Install dependencies
35
+ npm install
61
36
 
62
- ### Optional / Native Fallback Paths (Surgically Supported)
63
- The dashboard operates on a **"Native First, Fallback Second"** architecture. If any of the following calculated paths are transmitted natively by your boat's instruments, the dashboard will utilize them directly to preserve their calibration. If they are missing, the system silently activates its own local vector formulas:
37
+ # Start Vite development server (Port 3000)
38
+ npm run dev
64
39
 
65
- * `environment.wind.speedTrue` (**Optional** - Native True Wind Speed in m/s; falls back to local calculation if missing)
66
- * `environment.wind.directionTrue` (**Optional** - Native True Wind Direction in radians; falls back to local calculation if missing)
67
- * `navigation.headingMagnetic` (**Optional** - Magnetic Heading; automatically used if True Heading is missing on the network)
68
- * `navigation.magneticVariation` (**Optional** - Magnetic Variation; used to calibrate the Magnetic Heading fallback to True)
40
+ # Production build
41
+ npm run build
42
+ ```
69
43
 
70
44
  ---
71
45
 
72
- ## Installation
73
-
74
- The dashboard is distributed as a standard Signal K Node Server plugin and Web App.
75
-
76
- ### Installation via Signal K App Store (Recommended)
77
- 1. Access your Signal K admin panel (`http://<boat-ip>:3000`).
78
- 2. Navigate to **App Store** -> **Available**.
79
- 3. Search for `@sailingrotevista/rotevista-dash` and click **Install**.
80
- 4. Go to **Plugins Config**, activate the **Rotevista Dash Configuration** plugin, and configure your boat's safety thresholds (Draft, alarm offsets, and strategic chart timelines).
81
- 5. Click **Save**. The Signal K server will restart, apply the configurations, and initiate background history logging in RAM.
82
-
83
- ### Accessing the Dashboard
84
- Once installed, the dashboard is accessible on your local network by typing into your tablet or computer browser:
85
- ```text
86
- http://<boat-ip>:3000/@sailingrotevista/rotevista-dash/
87
- For the best experience in the cockpit, tap your browser's share button and select "Add to Home Screen" to run it as a standalone, distraction-free application.
46
+ ## License
88
47
 
89
- License
90
48
  This project is licensed under the MIT License - see the LICENSE file for details.
package/index.js CHANGED
@@ -76,6 +76,20 @@ module.exports = function (app) {
76
76
  };
77
77
  res.json(responseData);
78
78
  });
79
+
80
+ // Fallback static mount per Signal K per garantire che /rotevista-dash serva sempre la cartella public
81
+ try {
82
+ const path = require('path');
83
+ const express = require('express');
84
+ const publicPath = path.join(__dirname, 'public');
85
+ if (typeof app.use === 'function') {
86
+ app.use('/rotevista-dash', express.static(publicPath));
87
+ app.use('/@sailingrotevista/rotevista-dash', express.static(publicPath));
88
+ }
89
+ } catch (err) {
90
+ app.debug(`[rotevista-dash] Notice on static fallback: ${err.message}`);
91
+ }
92
+
79
93
  routeRegistered = true;
80
94
  app.debug('Public API endpoints registered at /rotevista-config and /rotevista-history');
81
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "7.0.45",
3
+ "version": "8.0.2",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -15,5 +15,30 @@
15
15
  "signalk": {
16
16
  "displayName": "Rotevista Wind Dashboard",
17
17
  "appIcon": "icons/dash.png"
18
+ },
19
+ "scripts": {
20
+ "dev": "vite --host 0.0.0.0 --port 3000",
21
+ "build": "vite build && mkdir -p dist && cp -r public/. dist/",
22
+ "prepublishOnly": "npm run build",
23
+ "lint": "tsc --noEmit",
24
+ "preview": "vite preview --host 0.0.0.0 --port 3000"
25
+ },
26
+ "files": [
27
+ "index.js",
28
+ "public",
29
+ "icons",
30
+ "manifest.json",
31
+ "settings.json"
32
+ ],
33
+ "dependencies": {
34
+ "react": "^19.3.1",
35
+ "react-dom": "^19.3.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/react": "^19.3.0",
39
+ "@types/react-dom": "^19.3.0",
40
+ "@vitejs/plugin-react": "^6.1.2",
41
+ "typescript": "^7.0.2",
42
+ "vite": "^8.3.4"
18
43
  }
19
44
  }
Binary file
@@ -0,0 +1 @@
1
+ html,body,#root{color:#000;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background-color:#fff;width:100vw;height:100vh;margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial,sans-serif;overflow:hidden}.main-container{box-sizing:border-box;grid-template:"stw gauge depth"1.75fr"sog gauge tws"1.75fr"hdg gauge twa".75fr"cog gauge awa".75fr"tack gauge twd"1.25fr/1fr 1.5fr 1fr;gap:8px;width:100%;height:100%;padding:5px;transition:all .5s cubic-bezier(.4,0,.2,1);display:grid}.box-stw{grid-area:stw}.box-sog{grid-area:sog}.box-hdg{grid-area:hdg}.box-cog{grid-area:cog}.box-tack{grid-area:tack}.box-gauge{grid-area:gauge;justify-content:center;align-items:center;display:flex;position:relative}.box-depth{grid-area:depth}.box-tws{grid-area:tws}.box-twa{grid-area:twa}.box-awa{grid-area:awa}.box-twd{grid-area:twd}.data-box{box-sizing:border-box;cursor:pointer;background:#00000008;border-bottom:1px solid #eee;border-radius:12px;flex-direction:column;width:100%;min-height:0;padding:.75rem 8px 3px;transition:background-color .2s;display:flex;position:relative;overflow:hidden;container-type:size;justify-content:center!important}.label-row{z-index:10;align-items:baseline;display:flex;position:absolute;top:3px;left:8px;right:8px}.label{color:#888;text-transform:uppercase;font-size:.65rem;font-weight:700}.unit{color:#aaa;font-size:.6rem;font-weight:700}.box-stw,.box-sog,.box-hdg,.box-cog,.box-tack{text-align:left!important;align-items:flex-start!important}.box-stw .label-row,.box-sog .label-row,.box-hdg .label-row,.box-cog .label-row,.box-tack .label-row{flex-direction:row!important;justify-content:space-between!important}.box-depth,.box-tws,.box-twa,.box-awa,.box-twd{text-align:right!important;align-items:flex-end!important;padding-left:8px!important;padding-right:8px!important}.box-depth .label-row,.box-tws .label-row,.box-twa .label-row,.box-awa .label-row,.box-twd .label-row{flex-direction:row-reverse!important;justify-content:space-between!important}.value,.value-large,.dual-val{font-variant-numeric:tabular-nums}.value{color:#000;letter-spacing:-.8px;margin-top:auto;margin-bottom:2px;font-size:clamp(1.35rem,38cqh,56cqw);font-weight:600;line-height:.82}@media screen and (height<=450px){.value{font-size:clamp(1.15rem,28cqh,46cqw)!important}}.value-large{margin:auto 0;font-weight:600;line-height:.95;white-space:nowrap!important;font-size:clamp(1.65rem,64cqh,40cqw)!important}@media screen and (height<=450px){.value-large{font-size:clamp(1.35rem,50cqh,34cqw)!important}}.value-with-compass{box-sizing:border-box;flex-direction:row;justify-content:space-between;align-items:center;gap:8px;width:100%;height:92%;padding:0 4px;display:flex}.box-twd .mini-compass{filter:drop-shadow(0 2px 5px #0000001f);flex-shrink:0;aspect-ratio:1!important;width:min(88cqh,38cqw)!important;height:min(88cqh,38cqw)!important}@media screen and (height<=450px){.box-twd .mini-compass{width:min(76cqh,32cqw)!important;height:min(76cqh,32cqw)!important}.box-twd #twd-avg,.box-twd .value-large{font-size:clamp(1.2rem,46cqh,22cqw)!important}}.box-twd .value-large,.box-twd #twd-avg{letter-spacing:-.5px;flex-shrink:1;white-space:nowrap!important;text-align:right!important;font-size:clamp(1.4rem,54cqh,25cqw)!important}.box-tack .dual-value-container{flex-direction:row;justify-content:space-between;align-items:center;width:100%;height:100%;display:flex}.box-tack .dual-value-col{flex-direction:column;justify-content:center;display:flex}.box-tack .dual-value-col:first-child{align-items:flex-start}.box-tack .dual-value-col:last-child{align-items:flex-end}.box-tack .dual-label{color:#888;margin-bottom:-1px;font-size:.55rem;font-weight:800}.box-tack .value.dual-val{line-height:.88;font-size:clamp(1.2rem,42cqh,24cqw)!important}@media screen and (height<=450px){.box-tack .value.dual-val{font-size:clamp(1rem,34cqh,18cqw)!important}}.alarm-warning{color:#e67e22!important}.alarm-danger{color:#c0392b!important}.blink-alarm{animation:.8s infinite alternate blink-depth}@keyframes blink-depth{0%{opacity:1}to{opacity:.3}}body.night-mode .alarm-danger{color:red!important;text-shadow:0 0 10px #f00c!important}.focus-active .data-box:not(.is-focused),.focus-active .box-gauge{display:none!important}.focus-active.focus-side-left{grid-template:"focused gauge"100%/3.2fr 1.8fr!important}.focus-active.focus-side-right{grid-template:"gauge focused"100%/1.8fr 3.2fr!important}.focus-active .is-focused{background:#00000005!important;grid-area:focused!important;justify-content:center!important;height:100vh!important;padding:1.2vh 1.8vw!important}.focus-active .is-focused .scale-labels{color:#444!important;min-width:55px!important;font-size:clamp(14px,2.2vw,26px)!important}.focus-active .is-focused .graph-wrapper{flex-grow:1.4!important;margin-top:10px!important}.focus-active .is-focused.box-hercules{box-shadow:inset 0 0 30px #ff00001a;background:#ff00001f!important}.focus-active .is-focused .value{margin-top:8px!important;font-size:clamp(4.5rem,36cqh,16rem)!important}.focus-active .is-focused .value-large{font-size:clamp(5rem,64cqh,18rem)!important}.focus-active .box-gauge{grid-area:gauge!important;display:flex!important}@media screen and (aspect-ratio>=.86) and (aspect-ratio<=1.25){.main-container{grid-template:"stw gauge gauge depth"1.6fr"sog gauge gauge tws"1.6fr"hdg gauge gauge twa"1.05fr"cog tack twd awa"1.05fr/1fr 1fr 1fr 1fr!important}.value{white-space:nowrap!important;font-size:clamp(1.2rem,30cqh,40cqw)!important}.value-large{white-space:nowrap!important;font-size:clamp(1.35rem,50cqh,34cqw)!important}.box-cog,.box-tack,.box-twd,.box-awa{border-top:1px solid #eee;background:#0000000a!important}.box-tack .dual-value-container{flex-direction:column!important;justify-content:center!important;align-items:flex-start!important;gap:4px!important}.box-tack .dual-value-col{text-align:left!important;flex-direction:column!important;align-items:flex-start!important;width:100%!important;display:flex!important}.box-tack .value.dual-val{white-space:nowrap!important;font-size:clamp(1.05rem,32cqh,21cqw)!important;line-height:1!important}.box-tack .dual-label{margin-bottom:0!important}.box-twd .value-with-compass{box-sizing:border-box;flex-direction:row;justify-content:space-between;align-items:center;gap:6px;height:96%;padding:0 3px;display:flex}.box-twd .mini-compass{filter:drop-shadow(0 2px 6px #00000026);flex-shrink:0;aspect-ratio:1!important;width:min(94cqh,48cqw)!important;height:min(94cqh,48cqw)!important}.box-twd #twd-avg,.box-twd .value-large{letter-spacing:-.5px;flex-shrink:1;margin-left:auto;font-weight:700;white-space:nowrap!important;text-align:right!important;font-size:clamp(1.2rem,54cqh,25cqw)!important}}.graph-wrapper{background:#0000000a;border-radius:4px;flex-direction:row;flex-grow:1;align-items:stretch;width:100%;min-height:0;margin-top:5px;display:flex;position:relative}.sparkline{flex-grow:1;height:100%;background:0 0!important;width:100%!important}.graph-wrapper polygon,.graph-wrapper line{shape-rendering:geometricprecision}.graph-wrapper polygon{filter:drop-shadow(0 0 2px #0000000d)}.scale-labels{color:#666;z-index:5;font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;flex-direction:column;flex-shrink:0;justify-content:space-between;width:auto;min-width:auto;height:100%;font-size:9.5px;font-weight:800;line-height:1;display:flex}.box-stw .sparkline,.box-sog .sparkline{order:1}.box-stw .scale-labels,.box-sog .scale-labels{text-align:right;order:2;padding-left:3px;padding-right:4px}.box-depth .scale-labels,.box-tws .scale-labels{text-align:left;order:1;padding-left:4px;padding-right:3px}.box-depth .sparkline,.box-tws .sparkline{order:2}.box-hercules{background:#ff00000d!important}.box-hercules .scale-labels{color:#f55}.box-hercules .unit:before{color:#f44;letter-spacing:1px;text-transform:uppercase;content:"HERCULES ";font-size:7px;font-weight:900}.line-hercules{filter:drop-shadow(0 0 5px red)}@media screen and (aspect-ratio<=.85){.main-container{grid-template:"gauge gauge"40vh"stw depth"1.75fr"sog tws"1.75fr"hdg twa".75fr"cog awa".75fr"tack twd"1.25fr/1fr 1fr!important}.data-box{height:auto!important}.box-stw,.box-sog,.box-depth,.box-tws{justify-content:flex-start!important;padding-top:1rem!important}.box-stw .value,.box-sog .value,.box-depth .value,.box-tws .value{font-weight:700;margin-top:-2px!important;margin-bottom:2px!important;padding-bottom:0!important;font-size:clamp(1.35rem,34cqh,50cqw)!important;line-height:.82!important}.box-stw .graph-wrapper,.box-sog .graph-wrapper,.box-depth .graph-wrapper,.box-tws .graph-wrapper{flex-grow:1!important;margin-top:0!important}.box-hdg,.box-cog,.box-twa,.box-awa,.box-twd,.box-tack{justify-content:center!important;padding-top:1rem!important}.box-hdg .value-large,.box-cog .value-large,.box-twa .value-large,.box-awa .value-large{white-space:nowrap!important;font-size:clamp(1.6rem,62cqh,40cqw)!important}.box-twd .value-with-compass{box-sizing:border-box;flex-direction:row;justify-content:space-between;align-items:center;gap:8px;height:94%;padding:0 4px;display:flex}.box-twd .mini-compass{filter:drop-shadow(0 2px 6px #00000026);flex-shrink:0;aspect-ratio:1!important;width:min(92cqh,46cqw)!important;height:min(92cqh,46cqw)!important}.box-twd .value-large,.box-twd #twd-avg{letter-spacing:-.5px;margin-left:auto;font-weight:700;white-space:nowrap!important;font-size:clamp(1.45rem,58cqh,28cqw)!important}.main-container.focus-active{grid-template:"focused"65vh"gauge"35vh/1fr!important}.focus-active .is-focused{justify-content:center!important;width:100vw!important;height:65vh!important;padding:5vh 5vw!important}.focus-active .is-focused .value{margin-top:20px!important;font-size:clamp(4rem,20cqh,15rem)!important}.focus-active .box-gauge{justify-content:center;align-items:center;width:100vw!important;height:35vh!important;display:flex!important}.box-tack .dual-value-container{flex-direction:row!important;justify-content:space-between!important;align-items:center!important}.box-tack .dual-value-col{justify-content:center;flex-direction:column!important;display:flex!important}.box-tack .dual-value-col:first-child{text-align:left!important;align-items:flex-start!important}.box-tack .dual-value-col:last-child{text-align:right!important;align-items:flex-end!important}.box-tack .value.dual-val{font-size:clamp(1.15rem,40cqh,22cqw)!important}}#status{text-transform:uppercase;z-index:1000;letter-spacing:1px;-webkit-user-select:none;user-select:none;background:#00000014;border-radius:4px;padding:3px 8px;font-size:.6rem;font-weight:900;position:absolute;top:15px;right:15px}.online{color:#27ae60;opacity:.9}.offline{color:#c0392b;font-weight:700}.simulating{color:#d97706;font-weight:700}.mini-compass{display:block;overflow:visible}.mini-compass .mini-boat-hull{fill:#1e293b;stroke:#fff;stroke-width:.8px;opacity:1}.mini-compass .mini-wind-chevron{stroke:#0284c7}body.night-mode .mini-compass-bezel{fill:#1c0000!important;stroke:#4a0000!important}body.night-mode .mini-compass-dial{fill:#0e0000!important;stroke:#3a0000!important}body.night-mode .mini-cardinal-n{fill:#f22!important}body.night-mode .mini-cardinal{fill:#800!important}body.night-mode .mini-tick{stroke:#500!important}body.night-mode .mini-boat-hull{fill:#300!important;stroke:#f22!important;opacity:1!important}body.night-mode #twd-wind-chevron{stroke:#f44!important}#wind-gauge circle[fill=\#050505]{fill:#fcfcfc}#wind-gauge circle[fill=\#121212]{fill:#f0f0f0}#boat-icon{opacity:1;fill:#000!important}#tick-labels{fill:#444!important}#aws-val-svg{fill:#000!important}#aws-display-group text{fill:#333!important}#fullscreen-hotspot{fill:#eee!important;stroke:#ccc!important}#ticks line[stroke=\#fff]{stroke:#000!important}#ticks line[stroke=\#666]{stroke:#bbb!important}rect[fill=\#222]{fill:#eee!important}#leeway-val{color:#000!important}#wind-gauge{object-fit:contain;width:100%;height:100%;max-height:100%}body.night-mode,.night-mode #root,.night-mode .main-container{color:#f33!important;background-color:#000!important}.night-mode .data-box{background:#14000066!important;border-color:#400!important;box-shadow:inset 0 0 15px #ff00000d!important}.night-mode .label,.night-mode .unit,.night-mode .dual-label{color:maroon!important}.night-mode .value-large{color:#f33!important;text-shadow:0 0 8px #f006!important}.night-mode .value{color:#f33;text-shadow:0 0 8px #ff00004d}.night-mode #status{color:#f33!important;background:#ff00001a!important}.night-mode #status.simulating{color:#f59e0b!important}.night-mode .graph-wrapper{border:1px solid #300;background:#0a0000cc!important}.night-mode .sparkline line[stroke="rgba(0,0,0,0.12)"],.night-mode .sparkline line[stroke="rgba(0,0,0,0.08)"]{stroke:#ff00001a!important}.night-mode .graph-wrapper svg{filter:brightness(.6)contrast(1.2)}.night-mode .graph-wrapper line[style]{filter:drop-shadow(0 0 2px #ff00004d);stroke-width:1px!important}.night-mode .scale-labels{color:maroon!important}.night-mode .is-focused .scale-labels{color:#f33!important}.night-mode #wind-gauge circle:not(#trend-gauge-cw):not(#trend-gauge-ccw){fill:#000!important;stroke:#200!important}.night-mode #wind-gauge>circle:nth-of-type(2),.night-mode #fullscreen-hotspot{fill:#050000!important;stroke:#300!important}.night-mode #trend-gauge-cw[fill=\#bbb],.night-mode #trend-gauge-ccw[fill=\#bbb],.night-mode #trend-gauge-cw[fill=\#bbbbbb],.night-mode #trend-gauge-ccw[fill=\#bbbbbb]{fill:#400!important;stroke:none!important;filter:none!important;opacity:.3!important}.night-mode #trend-gauge-cw[fill=\#27ae60],.night-mode #trend-gauge-ccw[fill=\#27ae60]{fill:#00c851!important;stroke:none!important;filter:drop-shadow(0 0 5px #00c851)!important;opacity:1!important}.night-mode #trend-gauge-cw[fill=\#c0392b],.night-mode #trend-gauge-ccw[fill=\#c0392b],.night-mode #trend-gauge-cw.is-gybing,.night-mode #trend-gauge-ccw.is-gybing{fill:#ff3b30!important;stroke:none!important;filter:drop-shadow(0 0 5px #ff3b30)!important;opacity:1!important}.night-mode #center-glow feDropShadow{flood-color:red!important;flood-opacity:.6!important}.night-mode #boat-icon{fill:#200!important;stroke:red!important;stroke-width:.8px!important;opacity:1!important}.night-mode #aws-display-group text{fill:maroon!important}.night-mode #aws-val-svg{fill:#f33!important}.night-mode #ticks line{stroke:#500!important}.night-mode #tick-labels{fill:maroon!important}.night-mode #wind-gauge path[stroke=\#ff0000]{opacity:.8;stroke:maroon!important}.night-mode #wind-gauge path[stroke=\#00ff00]{opacity:.7;stroke:#400!important;stroke-dasharray:5 4!important}.night-mode #wind-gauge path[stroke=\#ff8800]{opacity:.6;stroke:#300!important}.night-mode #awa-pointer path{fill:red!important;stroke:#000!important}.night-mode #twa-pointer path{fill:maroon!important;stroke:#000!important}.night-mode #track-pointer path{fill:#f33!important;stroke:none!important}.night-mode #leeway-val{fill:#f33!important;color:#f33!important}.night-mode rect[fill="url(#leeway-grad)"]{fill:url(#leeway-night-grad)!important}.night-mode rect[fill=\#eee],.night-mode rect[fill=\#222]{fill:#0a0000!important;stroke:#300!important}.night-mode g[stroke=\#555] line{stroke:#400!important}.night-mode g[fill=\#555] text{fill:maroon!important}.night-mode .mini-compass{background:0 0!important;border:none!important}.night-mode .mini-compass .mini-compass-dial{fill:#000!important;stroke:#300!important}.night-mode .mini-compass text{fill:maroon!important}.night-mode .mini-compass text:last-of-type{opacity:1;fill:maroon!important}.night-mode #twd-boat-wrap path{fill:#f33!important;opacity:.4!important}.night-mode #twd-arrow #twd-wind-chevron{stroke:#f33!important}.night-mode circle[fill=\#bbb]:not(#trend-gauge-cw):not(#trend-gauge-ccw),.night-mode circle[fill=\#bbbbbb]:not(#trend-gauge-cw):not(#trend-gauge-ccw){fill:#400!important}.night-mode circle[fill=\#27ae60]:not(#trend-gauge-cw):not(#trend-gauge-ccw){fill:red!important}.night-mode circle[fill=\#c0392b]:not(#trend-gauge-cw):not(#trend-gauge-ccw){fill:maroon!important}@keyframes blink-trend{0%,to{opacity:1}50%{opacity:0}}#trend-dot-cw,#trend-dot-ccw,#trend-gauge-cw,#trend-gauge-ccw{opacity:.3;transition:opacity .3s}.is-trending{opacity:1!important;animation:1s infinite blink-trend!important}.is-gybing{opacity:1!important;filter:drop-shadow(0 0 8px red)!important;animation:none!important}.unstable-data{animation:1.5s ease-in-out infinite blink-trend;color:#e67e22!important}.night-mode .graph-wrapper line[style*=\#2c3e50]{stroke:#6c8ea0!important}.night-mode .graph-wrapper polygon[style*=\#2c3e50]{fill:#6c8ea0!important}.night-mode .graph-wrapper line[style*=\#0088cc]{stroke:#3ad!important}.night-mode .graph-wrapper polygon[style*=\#0088cc]{fill:#3ad!important}#wind-gauge,#wind-radar{object-fit:contain;width:100%;height:100%;max-height:100%;transition:opacity .2s ease-in-out}.night-mode #wind-radar circle:not(.is-trending){fill:#000!important;stroke:#200!important}.night-mode #wind-radar circle:nth-of-type(2):not(.is-trending),.night-mode #radar-hotspot{fill:#050000!important;stroke:#300!important}.night-mode #radar-tick-labels{fill:maroon!important}.night-mode #radar-boat-icon{fill:#200!important;stroke:red!important;stroke-width:.8px!important;opacity:1!important}.night-mode #ora-orbit{stroke:#300!important}.night-mode #wind-radar circle[stroke=\#b0bec5]{stroke:#400!important}.wind-gauge-container{justify-content:center;align-items:center;width:100%;height:100%;max-height:100%;display:flex;position:relative}