diff --git a/src/web/www/overview.html b/src/web/www/overview.html index 59153dc..4bc377c 100644 --- a/src/web/www/overview.html +++ b/src/web/www/overview.html @@ -423,7 +423,12 @@ .ov-perf-name { font-size: 12px; font-weight: 700; - letter-spacing: 0.4px; + /* UPPERCASE to match the chain's stage labels (INPUT/PROCESS/OUTPUT), which + are text-transform:uppercase. Owner consistency ruling 2026-08-17: every + card header in the signal chain reads uppercase, so this one does too. + Letter-spacing bumped to sit with the stage labels' 1.4px feel. */ + letter-spacing: 1.2px; + text-transform: uppercase; color: var(--info-text); margin-bottom: 8px; padding-bottom: 6px; @@ -439,6 +444,15 @@ } .ov-perf-row .ov-perf-k { color: var(--text-muted); } .ov-perf-row .ov-perf-v { color: var(--text-primary); } +/* Threshold colouring for the RF Performance values, matching the dashboard's + scheme (owner, 2026-08-17). Same tokens the dashboard uses (value-ok/warn/err/ + off resolve to these), so a below-threshold reading turns the same colour here + as on the dashboard. Status is computed by the dashboard's OWN getSnrStatus/ + getImdStatus (one source of truth), not re-thresholded here. */ +.ov-perf-row .ov-perf-v.ov-v-ok { color: var(--accent-green); } +.ov-perf-row .ov-perf-v.ov-v-warn { color: var(--status-warn); } +.ov-perf-row .ov-perf-v.ov-v-err { color: var(--status-err); } +.ov-perf-row .ov-perf-v.ov-v-off { color: var(--text-muted); } .ov-perf-foot { margin-top: auto; padding-top: 10px; @@ -768,13 +782,24 @@ function fbArrow() { box's full width and can wrap without clipping. Values pass through exactly as parse() produced them, so 'N/A-FSSI' shows verbatim under FSSI Refresh. */ function perfBox(snr, limd, uimd) { + /* Colour each value by the dashboard's OWN threshold functions (getSnrStatus: + >=27 ok / >=20 warn / else err; getImdStatus: >=47 ok / else err; 'N/A*' -> + off/grey). One source of truth shared with the dashboard, so the box and the + dashboard never disagree. The status maps to ov-v-* (same colours as the + dashboard's value-* tokens). SNR can go amber; the IMDs jump straight to red, + exactly as the dashboard treats them. */ + var H = window.DashboardHelpers; + var vc = function(cls){ return 'ov-perf-v' + (cls ? ' ov-v-' + cls : ''); }; + var snrC = vc(H.getSnrStatus(snr)); + var limdC = vc(H.getImdStatus(limd)); + var uimdC = vc(H.getImdStatus(uimd)); return '' + '
' + '
RF Performance
' + '
Sampled transmit signal
' + - '
SNR' + snr + ' dB
' + - '
LIMD' + limd + ' dBc
' + - '
UIMD' + uimd + ' dBc
' + + '
SNR' + snr + ' dB
' + + '
LIMD' + limd + ' dBc
' + + '
UIMD' + uimd + ' dBc
' + '
Details ›
' + '
'; } @@ -861,9 +886,13 @@ window.Trends = (function () { /* Chart set per sub-mode. Order = display order. Duplicated from the 1.0 verbatim per the owner's law (exciter 5 charts / translator 7). smod has only these two modes, so only these two are defined. */ + /* Chart set per sub-mode. Order = display order. LIMD before UIMD (lower + intermodulation product first, then upper) — owner-ruled 2026-08-17. The + 1.0 has these reversed (uimd, limd); that is logged as a cross-product fix, + NOT copied here. smod has only these two modes. */ var CHARTS_FOR_MODE = { - exciter: ['input_bitrate', 'snr', 'fwd_pct', 'uimd', 'limd'], - translator: ['input_bitrate', 'rsnr', 'rssi', 'snr', 'fwd_pct', 'uimd', 'limd'] + exciter: ['input_bitrate', 'snr', 'fwd_pct', 'limd', 'uimd'], + translator: ['input_bitrate', 'rsnr', 'rssi', 'snr', 'fwd_pct', 'limd', 'uimd'] }; var SPARK_W = 200, SPARK_H = 40, SPARK_PAD_Y = 2; diff --git a/src/web/www/sys_spectrum.html b/src/web/www/sys_spectrum.html index 35f134f..0e0eab9 100755 --- a/src/web/www/sys_spectrum.html +++ b/src/web/www/sys_spectrum.html @@ -210,9 +210,28 @@ negative). Verified: raw -22.7 -> -33.7 vs IMD 32.3/32.5; raw ~-63.4 -> -74.4 vs IMD 73.6/73.9. */ var IMD_PILOT_OFFSET = 11; // dB; documented pilot offset (1.0 status_info_new.html) - setReadout('rd_shoulder', d.shoulder - IMD_PILOT_OFFSET, 1); - setReadout('rd_limd', d.limd + IMD_PILOT_OFFSET, 1); - setReadout('rd_uimd', d.uimd + IMD_PILOT_OFFSET, 1); + /* Threshold colouring for the three shoulder-suppression readouts, to match + the dashboard's scheme (owner, 2026-08-17). The dashboard colours SNR/LIMD/ + UIMD via getSnrStatus/getImdStatus; SNR here is already coloured below + (line ~303). LIMD and UIMD use the dashboard's IMD rule directly: >= 47 dBc + green, else red (they already carry the +11 offset so they match the + dashboard values). Shoulder has NO pre-existing threshold anywhere; owner + ruled it uses the SAME 47 dBc line as the IMDs on its ABSOLUTE value (it is + the same kind of dBc shoulder-suppression measure, only signed negative). All + OTHER spectrum readouts (FSSI, Pilot, Peak, RBW, ...) stay plain — no invented + thresholds. A '--'/NaN reading clears the colour (stays default), never red. */ + function imdColour(v){ // dBc magnitude vs the 47 dBc pass line + return (v === null) ? '' : (Math.abs(v) >= 47 ? 'var(--accent-green)' : 'var(--status-err)'); + } + var shoulderVal = setReadout('rd_shoulder', d.shoulder - IMD_PILOT_OFFSET, 1); + var limdVal = setReadout('rd_limd', d.limd + IMD_PILOT_OFFSET, 1); + var uimdVal = setReadout('rd_uimd', d.uimd + IMD_PILOT_OFFSET, 1); + var shoulderEl = document.getElementById('rd_shoulder'); + var limdEl = document.getElementById('rd_limd'); + var uimdEl = document.getElementById('rd_uimd'); + if (shoulderEl) shoulderEl.style.color = imdColour(shoulderVal); + if (limdEl) limdEl.style.color = imdColour(limdVal); + if (uimdEl) uimdEl.style.color = imdColour(uimdVal); setReadout('rd_pilot', d.pilot, 4); setReadout('rd_peak', d.peak, 1); setReadout('rd_rbw', d.rbw_khz, 2);