// Cold Spot Detector / Atmospheric Disturbance Index — the per-device
// visual layer over lib/coldSpot.ts's pure classifiers. DevicesPage.tsx
// owns and updates the rolling-baseline state as `reading` frames arrive
// (mirrors GhostLog.tsx owning tell history and handing the *result* of
// computeEvilMeter down to its gauge); this component is purely
// presentational — given a device's current temperature/pressure readouts
// (or null, if that sensor_type has never reported), it renders the
// frost/ripple treatments, callouts, sparkline and composite gauge, and
// renders nothing for a sensor that has never reported. A device with
// neither sensor renders nothing at all.
import { useId } from 'react'
import { useTranslation } from 'react-i18next'
import { disturbanceIndex, disturbanceLabel } from '../lib/coldSpot'
import './ColdSpotPanel.css'
export type TemperatureReadout = {
value: number
unit: string
deviation: number | null
isColdSpot: boolean
severity: number
}
export type PressureReadout = {
value: number
unit: string
deviation: number | null
isPressureAnomaly: boolean
severity: number
direction: 'rise' | 'drop'
}
type ColdSpotPanelProps = {
temperature: TemperatureReadout | null
pressure: PressureReadout | null
/** Recent temperature samples, oldest first — see lib/coldSpot.ts's
* pushSample/SPARKLINE_SAMPLE_CAP. */
tempSparkline: readonly number[]
}
function clamp01(n: number): number {
return Math.min(1, Math.max(0, n))
}
export function ColdSpotPanel({ temperature, pressure, tempSparkline }: ColdSpotPanelProps) {
if (!temperature && !pressure) return null
const bothReported = temperature !== null && pressure !== null
return (