@@ -569,38 +569,65 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
569569 * @constant {Object<string, Array<string>>}
570570 */
571571 const WINTER_WEATHER_SYNONYMS = {
572- // Official NWS alert types
572+ // Official NWS alert types - comprehensive list
573573 alerts : [
574+ // Advisories
574575 'winter weather advisory' ,
576+ 'freezing rain advisory' ,
577+ 'snow advisory' ,
578+ 'wind chill advisory' ,
579+ 'frost advisory' ,
580+ 'lake effect snow advisory' ,
581+ 'winter weather statement' ,
582+ // Warnings
575583 'winter storm warning' ,
576- 'winter storm watch ' ,
584+ 'winter weather warning ' ,
577585 'ice storm warning' ,
578- 'ice storm watch' ,
579586 'blizzard warning' ,
580- 'blizzard watch' ,
581- 'freezing rain advisory' ,
582- 'snow advisory' ,
583587 'wind chill warning' ,
584- 'wind chill advisory' ,
585588 'freeze warning' ,
586- 'frost advisory'
589+ 'freezing rain warning' ,
590+ 'snow squall warning' ,
591+ 'lake effect snow warning' ,
592+ 'extreme cold warning' ,
593+ 'hard freeze warning' ,
594+ // Watches
595+ 'winter storm watch' ,
596+ 'ice storm watch' ,
597+ 'blizzard watch' ,
598+ 'wind chill watch' ,
599+ 'extreme cold watch' ,
600+ 'freeze watch' ,
601+ 'freezing rain watch' ,
602+ 'lake effect snow watch'
587603 ] ,
588- // Weather phenomena keywords
604+ // Weather phenomena keywords - comprehensive coverage
589605 phenomena : [
590- 'snow' , 'snowfall' , 'snowing' , 'snowstorm' ,
591- 'freezing rain' , 'freezing drizzle' ,
592- 'sleet' , 'sleeting' ,
593- 'ice' , 'icing' , 'black ice' ,
606+ // Snow terms
607+ 'snow' , 'snowfall' , 'snowing' , 'snowstorm' , 'snowfall' ,
608+ 'snow squall' , 'snow shower' , 'snow flurries' , 'flurries' ,
609+ 'blowing snow' , 'drifting snow' , 'snowdrift' ,
610+ 'lake effect snow' , 'upslope snow' ,
611+ 'accumulating snow' , 'snow accumulation' , 'snow totals' ,
612+ 'snowfall rates' , 'heavy snow' , 'significant snow' ,
613+ // Ice terms
614+ 'ice' , 'icing' , 'black ice' , 'glaze ice' ,
615+ 'freezing rain' , 'freezing drizzle' , 'freezing fog' ,
616+ 'ice accumulation' , 'ice buildup' , 'ice storm' ,
617+ 'ice formation' , 'ice coating' ,
618+ // Mixed precipitation
619+ 'sleet' , 'sleeting' , 'sleet pellets' ,
594620 'wintry' , 'wintry mix' , 'winter precipitation' ,
595- 'winter conditions' , 'winter weather' ,
596- 'accumulating snow' , 'snow accumulation' ,
597- 'ice accumulation' , 'ice buildup' ,
598- 'snowfall rates' , 'snow totals' ,
621+ 'freezing precipitation' , 'mixed precipitation' ,
622+ // Cold conditions
599623 'freezing temperatures' , 'below freezing' ,
600- 'wind chill' , 'windchill' ,
601- 'blizzard' , 'whiteout' ,
602- 'snow squall' , 'snow shower' ,
603- 'flurries' , 'wintry precipitation'
624+ 'wind chill' , 'windchill' , 'wind chill factor' ,
625+ 'extreme cold' , 'bitter cold' , 'dangerous cold' ,
626+ 'hard freeze' , 'freeze' , 'frost' ,
627+ // Visibility/conditions
628+ 'blizzard' , 'whiteout' , 'near-zero visibility' ,
629+ 'winter conditions' , 'winter weather' ,
630+ 'hazardous winter weather' , 'winter storm'
604631 ] ,
605632 // Timing/severity indicators
606633 severity : [
@@ -658,19 +685,30 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
658685 ? alert . properties . severity . toLowerCase ( )
659686 : '' ;
660687
661- // Check for warnings (highest priority)
662- if ( eventLower . includes ( 'warning' ) && ! eventLower . includes ( 'watch' ) && ! eventLower . includes ( 'advisory' ) ) {
688+ // Check for warnings (highest priority) - comprehensive detection
689+ // Look for "warning" keyword but exclude "watch" and "advisory" variations
690+ if ( eventLower . includes ( 'warning' ) &&
691+ ! eventLower . includes ( 'watch' ) &&
692+ ! eventLower . includes ( 'advisory' ) &&
693+ ! eventLower . includes ( 'statement' ) ) {
663694 hasWarning = true ;
695+ console . log ( `[Winter Weather] WARNING detected: "${ event } "` ) ;
664696 }
665697 // Check for advisories (lower priority)
666- else if ( eventLower . includes ( 'advisory' ) || ( eventLower . includes ( 'watch' ) && severity !== 'severe' ) ) {
698+ // Includes advisory, watch (unless severe), and statements
699+ else if ( eventLower . includes ( 'advisory' ) ||
700+ eventLower . includes ( 'statement' ) ||
701+ ( eventLower . includes ( 'watch' ) && severity !== 'severe' ) ) {
667702 hasAdvisory = true ;
703+ console . log ( `[Winter Weather] ADVISORY/WATCH detected: "${ event } "` ) ;
668704 }
669705 }
670706
671707 if ( hasWarning ) {
708+ console . log ( `[Winter Weather] Status determined: WARNING (has ${ hasWarning ? 'warning' : '' } , ${ hasAdvisory ? 'advisory' : '' } )` ) ;
672709 return { status : 'warning' , hasAdvisory : true , hasWarning : true } ;
673710 } else if ( hasAdvisory ) {
711+ console . log ( `[Winter Weather] Status determined: ADVISORY` ) ;
674712 return { status : 'advisory' , hasAdvisory : true , hasWarning : false } ;
675713 }
676714
@@ -711,25 +749,44 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
711749 }
712750 }
713751
714- // Check for official alert terminology in text
752+ // Check for official alert terminology in text (higher weight for official terms)
715753 for ( const alert of WINTER_WEATHER_SYNONYMS . alerts ) {
716754 if ( textLower . includes ( alert ) ) {
717755 score += 3 ;
718- if ( alert . includes ( 'warning' ) ) {
756+ // Check for warning terms (higher priority)
757+ if ( alert . includes ( 'warning' ) && ! alert . includes ( 'watch' ) && ! alert . includes ( 'advisory' ) ) {
719758 hasWarningTerms = true ;
720- } else if ( alert . includes ( 'advisory' ) ) {
759+ }
760+ // Check for advisory/watch/statement terms
761+ else if ( alert . includes ( 'advisory' ) || alert . includes ( 'watch' ) || alert . includes ( 'statement' ) ) {
721762 hasAdvisoryTerms = true ;
722763 }
723764 }
724765 }
725766
726767 // Determine status based on score and indicators
727768 if ( score >= 5 ) {
728- if ( hasWarningTerms || textLower . includes ( 'winter storm warning' ) || textLower . includes ( 'blizzard warning' ) ) {
769+ // Check for winter weather warning terms (comprehensive detection)
770+ const warningPatterns = [
771+ 'winter storm warning' , 'winter weather warning' , 'ice storm warning' ,
772+ 'blizzard warning' , 'freezing rain warning' , 'snow squall warning' ,
773+ 'wind chill warning' , 'extreme cold warning'
774+ ] ;
775+ const hasWarningPattern = warningPatterns . some ( pattern => textLower . includes ( pattern ) ) ;
776+
777+ if ( hasWarningTerms || hasWarningPattern ) {
778+ console . log ( '[Winter Weather] Text detection: WARNING status' ) ;
729779 return { status : 'warning' , confidence : Math . min ( score , 10 ) } ;
730- } else if ( hasAdvisoryTerms || textLower . includes ( 'winter weather advisory' ) ) {
780+ }
781+ // Check for advisory/watch/statement terms
782+ else if ( hasAdvisoryTerms ||
783+ textLower . includes ( 'winter weather advisory' ) ||
784+ textLower . includes ( 'winter storm watch' ) ||
785+ textLower . includes ( 'winter weather statement' ) ) {
786+ console . log ( '[Winter Weather] Text detection: ADVISORY status' ) ;
731787 return { status : 'advisory' , confidence : Math . min ( score , 8 ) } ;
732788 } else {
789+ console . log ( '[Winter Weather] Text detection: ADVISORY status (generic winter weather)' ) ;
733790 return { status : 'advisory' , confidence : Math . min ( score , 6 ) } ;
734791 }
735792 }
@@ -790,8 +847,14 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
790847 if ( data && data . features && Array . isArray ( data . features ) && data . features . length > 0 ) {
791848 // Detect winter weather from alerts
792849 const winterWeather = detectWinterWeatherFromAlerts ( data . features ) ;
850+ const previousWinterStatus = winterWeatherStatus ;
793851 winterWeatherStatus = winterWeather . status ;
794852
853+ // Debug: Log winter weather detection
854+ if ( winterWeatherStatus !== 'none' ) {
855+ console . log ( `Winter weather detected: ${ winterWeatherStatus } (was: ${ previousWinterStatus } )` ) ;
856+ }
857+
795858 // Filter alerts to show only warnings/watches/advisories with valid severity
796859 // Excludes informational statements and other non-actionable alerts
797860 // Validates alert structure before processing
@@ -966,6 +1029,7 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
9661029 threatColor = '#f44336' ;
9671030 description = 'Winter Precipitation Imminent and/or Occurring' ;
9681031 icon = '⚠️' ;
1032+ console . log ( '[Threat Level] Set to WARNING due to winter weather warning' ) ;
9691033 } else {
9701034 threatLevel = 'WARNING' ;
9711035 threatColor = '#f44336' ;
@@ -979,6 +1043,7 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
9791043 threatColor = '#FFEB3B' ;
9801044 description = 'Monitor for Winter Conditions' ;
9811045 icon = '❄️' ;
1046+ console . log ( 'Threat level set to MONITOR due to winter weather advisory' ) ;
9821047 }
9831048 // Priority 2: Enhanced/Moderate/High SPC risk levels
9841049 else if ( spcRiskLevel && [ 'ENH' , 'MDT' , 'HIGH' ] . includes ( spcRiskLevel ) ) {
@@ -1406,19 +1471,34 @@ <h3 style="margin: 0 0 15px 0; color: #ff7043; font-size: 1.4em; font-weight: 60
14061471 setInterval ( updateDashboard , updateInterval ) ;
14071472
14081473 // Independent 3-minute polling for alerts to keep them fresh
1409- // This allows warnings to appear quickly without waiting for full refresh
1474+ // This allows warnings and winter weather advisories to appear quickly without waiting for full refresh
14101475 setInterval ( async function ( ) {
14111476 try {
1477+ const previousWinterStatus = winterWeatherStatus ;
14121478 const hadWarnings = await updateLocalAlertsAndGetStatus ( ) ;
1413- // If warning state has changed, refresh threat card quickly
14141479 const currentThreat = document . getElementById ( 'threat-status' ) ?. textContent || '' ;
1415- if ( ( hadWarnings && currentThreat !== 'WARNING' ) || ( ! hadWarnings && currentThreat === 'WARNING' ) ) {
1480+
1481+ // Check if warning state has changed
1482+ const warningStateChanged = ( hadWarnings && currentThreat !== 'WARNING' ) || ( ! hadWarnings && currentThreat === 'WARNING' ) ;
1483+
1484+ // Check if winter weather status has changed
1485+ const winterStatusChanged = previousWinterStatus !== winterWeatherStatus ;
1486+
1487+ // Check if current threat level doesn't match the winter weather status
1488+ const threatMismatch = ( winterWeatherStatus === 'advisory' && currentThreat !== 'MONITOR' ) ||
1489+ ( winterWeatherStatus === 'warning' && currentThreat !== 'WARNING' ) ||
1490+ ( winterWeatherStatus === 'none' && previousWinterStatus !== 'none' && currentThreat !== 'SAFE' ) ;
1491+
1492+ // Update if any of these conditions are true
1493+ if ( warningStateChanged || winterStatusChanged || threatMismatch ) {
14161494 const prevLast = lastUpdate ;
14171495 lastUpdate = 0 ; // force refresh
14181496 await updateDashboard ( ) ;
14191497 lastUpdate = prevLast || Date . now ( ) ;
14201498 }
1421- } catch ( e ) { }
1499+ } catch ( e ) {
1500+ console . error ( 'Alert polling error:' , e ) ;
1501+ }
14221502 } , 180000 ) ;
14231503 document . addEventListener ( 'visibilitychange' , function ( ) {
14241504 if ( ! document . hidden && Date . now ( ) - lastUpdate > updateInterval ) {
0 commit comments