<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Weather and hazard monitoring dashboard for Pacific Northwest Tribal Nations">
  <title>PNW Tribal Dashboard | IndigenousACCESS</title>
 
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
 
<style>
/* ============================================================================
   GOOGLE FONTS - Poppins (Display) + Nunito Sans (Body)
   ============================================================================ */
@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600;700&family=Poppins:wght@500;600;700&display=swap');
 
/* ============================================================================
   CSS CUSTOM PROPERTIES - Glassmorphism Environmental Theme
   ============================================================================ */
:root {
  /* GLASSMORPHISM CORE */
  --glass-blur: blur(20px);
  --glass-bg: rgba(20, 20, 20, 0.6);
  --glass-bg-hover: rgba(30, 30, 30, 0.7);
  --glass-border: rgba(255, 255, 255, 0.08);
  --glass-border-hover: rgba(255, 255, 255, 0.15);
  --glass-border-glow: rgba(255, 255, 255, 0.2);
 
  /* Environmental Background Colors */
  --env-deep: #0a1628;
  --env-mid: #0d2847;
  --env-light: #1a4a6e;
  --env-accent: #2d6a8f;
  --env-highlight: rgba(100, 180, 220, 0.3);
 
  /* Text colors - WCAG AA compliant on glass */
  --text-primary: #ffffff;
  --text-secondary: rgba(255, 255, 255, 0.85);
  --text-muted: rgba(255, 255, 255, 0.65);
  --text-dim: rgba(255, 255, 255, 0.45);
 
  /* SEMANTIC DANGER LEVELS */
  --danger-safe: #22c55e;
  --danger-safe-bg: rgba(34, 197, 94, 0.15);
  --danger-safe-glow: 0 0 clamp(1rem, 2vw, 1.5rem) rgba(34, 197, 94, 0.4);
 
  --danger-watch: #eab308;
  --danger-watch-bg: rgba(234, 179, 8, 0.15);
  --danger-watch-glow: 0 0 clamp(1rem, 2vw, 1.5rem) rgba(234, 179, 8, 0.4);
 
  --danger-warning: #ef4444;
  --danger-warning-bg: rgba(239, 68, 68, 0.2);
  --danger-warning-glow: 0 0 clamp(1.25rem, 2.5vw, 2rem) rgba(239, 68, 68, 0.5);
 
  --danger-extreme: #dc2626;
  --danger-extreme-bg: rgba(220, 38, 38, 0.25);
  --danger-extreme-glow: 0 0 clamp(1.5rem, 3vw, 2.5rem) rgba(220, 38, 38, 0.6);
 
  /* Legacy mappings */
  --severity-none: var(--danger-safe);
  --severity-none-bg: var(--danger-safe-bg);
  --severity-none-glow: var(--danger-safe-glow);
  --severity-watch: var(--danger-watch);
  --severity-watch-bg: var(--danger-watch-bg);
  --severity-watch-glow: var(--danger-watch-glow);
  --severity-warning: var(--danger-warning);
  --severity-warning-bg: var(--danger-warning-bg);
  --severity-warning-glow: var(--danger-warning-glow);
  --severity-extreme: var(--danger-extreme);
  --severity-extreme-bg: var(--danger-extreme-bg);
  --severity-extreme-glow: var(--danger-extreme-glow);
 
  /* Accent colors */
  --accent-primary: #22d3ee;
  --accent-hover: #14b8a6;
  --accent-light: rgba(34, 211, 238, 0.15);
  --primary-cyan: #22d3ee;
  --primary-blue: #3b82f6;
  --primary-teal: #14b8a6;
 
  /* FLUID SPACING */
  --space-xs: clamp(0.125rem, 0.5vw, 0.25rem);
  --space-sm: clamp(0.25rem, 1vw, 0.5rem);
  --space-md: clamp(0.5rem, 1.5vw, 0.75rem);
  --space-lg: clamp(0.75rem, 2vw, 1rem);
  --space-xl: clamp(1rem, 3vw, 1.5rem);
  --space-2xl: clamp(1.5rem, 4vw, 2rem);
  --space-3xl: clamp(2rem, 5vw, 3rem);
 
  /* FLUID TYPOGRAPHY */
  --font-display: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-body: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
 
  --text-hero: clamp(2.5rem, 8vw, 5rem);
  --text-data-lg: clamp(1.75rem, 5vw, 3rem);
  --text-data-md: clamp(1.25rem, 3vw, 2rem);
  --text-heading: clamp(1rem, 2.5vw, 1.5rem);
  --text-body: clamp(0.875rem, 1.5vw, 1rem);
  --text-small: clamp(0.75rem, 1.25vw, 0.875rem);
  --text-micro: clamp(0.625rem, 1vw, 0.75rem);
 
  /* MODULAR GRID SYSTEM */
  --grid-gap: clamp(0.75rem, 2vw, 1.5rem);
  --grid-columns: 4;
  --strip-header-height: clamp(8vh, 10vh, 12vh);
 
  /* Border radius */
  --radius-sm: 0;
  --radius-md: 0;
  --radius-lg: 0;
 
  /* Shadows */
  --shadow-sm: 0 0.125rem 0.25rem rgba(0,0,0,0.3);
  --shadow-md: 0 0.25rem 0.75rem rgba(0,0,0,0.4);
  --shadow-lg: 0 0.5rem 1.5rem rgba(0,0,0,0.5);
  --shadow-glass: 0 0.5rem 2rem rgba(0, 0, 0, 0.3), inset 0 0.0625rem 0 rgba(255, 255, 255, 0.1);
  --shadow-glow: 0 0 2rem rgba(34, 211, 238, 0.2);
 
  /* River flood stage colors */
  --river-below: #78716c;
  --river-normal: var(--danger-safe);
  --river-action: var(--danger-watch);
  --river-near-flood: #f97316;
  --river-flooding: var(--danger-warning);
 
  /* Icon colors */
  --icon-default: rgba(255, 255, 255, 0.7);
  --icon-hover: rgba(255, 255, 255, 0.9);
  --icon-active: #ffffff;
 
  /* Legacy compatibility */
  --card-bg: var(--glass-bg);
  --card-bg-hover: var(--glass-bg-hover);
  --card-border: var(--glass-border);
  --card-border-hover: var(--glass-border-hover);
}
 
/* ============================================================================
   BASE STYLES
   ============================================================================ */
.flood-dashboard * {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
 
.flood-dashboard {
  font-family: var(--font-body);
  min-height: 100vh;
  padding: var(--space-lg);
  color: var(--text-primary);
  line-height: 1.6;
  position: relative;
  overflow-x: hidden;
 
  background:
    radial-gradient(ellipse 80% 50% at 20% 30%, var(--env-highlight) 0%, transparent 50%),
    radial-gradient(ellipse 60% 40% at 70% 60%, rgba(100, 150, 200, 0.15) 0%, transparent 45%),
    radial-gradient(ellipse 50% 30% at 40% 80%, rgba(80, 130, 180, 0.1) 0%, transparent 40%),
    linear-gradient(
      180deg,
      var(--env-deep) 0%,
      var(--env-mid) 35%,
      var(--env-light) 65%,
      var(--env-accent) 100%
    );
  background-size:
    200% 200%,
    180% 180%,
    150% 150%,
    100% 100%;
  animation: environmentDrift 45s ease-in-out infinite;
}
 
@keyframes environmentDrift {
  0%, 100% {
    background-position: 0% 0%, 100% 100%, 50% 50%, 0% 0%;
  }
  25% {
    background-position: 50% 25%, 25% 75%, 75% 25%, 0% 0%;
  }
  50% {
    background-position: 100% 50%, 50% 0%, 0% 75%, 0% 0%;
  }
  75% {
    background-position: 50% 75%, 75% 50%, 25% 0%, 0% 0%;
  }
}
 
.flood-dashboard::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 0%, rgba(0, 0, 0, 0.2) 100%);
  z-index: 0;
}
 
.flood-dashboard > * {
  position: relative;
  z-index: 1;
}
 
@media (min-width: 48rem) {
  .flood-dashboard { padding: var(--space-xl); }
}
 
@media (min-width: 75rem) {
  .flood-dashboard {
    max-width: 90rem;
    margin: 0 auto;
    padding: var(--space-2xl);
  }
}
 
/* GLASSMORPHISM CONTAINER */
.glass-container {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-glass);
  transition: all 0.3s ease;
}
 
.glass-container:hover {
  background: var(--glass-bg-hover);
  border-color: var(--glass-border-hover);
}
 
.glass-container.danger-safe { box-shadow: var(--shadow-glass), var(--danger-safe-glow); }
.glass-container.danger-watch { box-shadow: var(--shadow-glass), var(--danger-watch-glow); }
.glass-container.danger-warning { box-shadow: var(--shadow-glass), var(--danger-warning-glow); }
.glass-container.danger-extreme { box-shadow: var(--shadow-glass), var(--danger-extreme-glow); }
 
/* ============================================================================
   STRIP HEADER
   ============================================================================ */
.dashboard-header {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-glass);
 
  min-height: var(--strip-header-height);
  max-height: 15vh;
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-lg);
 
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  flex-wrap: wrap;
}
 
.header-title {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex: 1;
  min-width: 0;
}
 
.header-title h1 {
  font-family: var(--font-display);
  font-size: var(--text-heading);
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
 
.header-subtitle {
  font-size: var(--text-small);
  color: var(--text-secondary);
  line-height: 1.4;
  display: none;
}
 
@media (min-width: 64rem) {
  .header-subtitle {
    display: block;
    margin-left: var(--space-lg);
    padding-left: var(--space-lg);
    border-left: 1px solid var(--glass-border);
    max-width: 25vw;
  }
}
 
/* ============================================================================
   ALERT BANNER
   ============================================================================ */
.alert-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  border-radius: var(--radius-md);
  font-weight: 600;
  transition: all 0.3s ease;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
 
.alert-banner.status-none {
  background: var(--danger-safe-bg);
  border-left: clamp(0.1875rem, 0.5vw, 0.25rem) solid var(--danger-safe);
  color: #86efac;
  box-shadow: var(--shadow-glass), var(--danger-safe-glow);
}
 
.alert-banner.status-watch {
  background: var(--danger-watch-bg);
  border-left: clamp(0.1875rem, 0.5vw, 0.25rem) solid var(--danger-watch);
  color: #fde047;
  box-shadow: var(--shadow-glass), var(--danger-watch-glow);
}
 
.alert-banner.status-warning {
  background: var(--danger-warning-bg);
  border-left: clamp(0.1875rem, 0.5vw, 0.25rem) solid var(--danger-warning);
  color: #fca5a5;
  box-shadow: var(--shadow-glass), var(--danger-warning-glow);
  animation: pulse-warning 2s ease-in-out infinite;
}
 
@keyframes pulse-warning {
  0%, 100% { opacity: 1; box-shadow: var(--shadow-glass), var(--danger-warning-glow); }
  50% { opacity: 0.95; box-shadow: var(--shadow-glass), 0 0 clamp(2rem, 4vw, 3rem) rgba(239, 68, 68, 0.7); }
}
 
.alert-icon {
  font-size: var(--text-data-md);
  flex-shrink: 0;
}
 
.alert-content {
  flex: 1;
  min-width: 0;
}
 
.alert-link {
  color: inherit;
  text-decoration: none;
  display: block;
  cursor: pointer;
}
 
.alert-link:hover { text-decoration: underline; }
 
.alert-title {
  font-size: var(--text-body);
  margin-bottom: var(--space-xs);
}
 
.alert-detail {
  font-size: var(--text-small);
  font-weight: 400;
  opacity: 0.9;
}
 
/* ============================================================================
   TRIBAL SELECTOR
   ============================================================================ */
.selector-section {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
  box-shadow: var(--shadow-glass);
}
 
.selector-label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: var(--space-sm);
  font-size: var(--text-body);
}
 
.selector-hint {
  font-size: var(--text-small);
  color: var(--text-secondary);
  margin-bottom: var(--space-md);
  line-height: 1.5;
}
 
.tribe-select {
  width: 100%;
  padding: var(--space-md);
  font-size: var(--text-body);
  font-family: var(--font-body);
  border: 0.125rem solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.3);
  color: var(--text-primary);
  cursor: pointer;
  transition: all 0.2s ease;
  min-height: clamp(2.75rem, 6vh, 3rem);
}
 
.tribe-select:hover { border-color: var(--accent-primary); }
 
.tribe-select:focus {
  outline: none;
  border-color: var(--accent-primary);
  box-shadow: 0 0 0 clamp(0.125rem, 0.3vw, 0.1875rem) var(--accent-light);
}
 
.state-buttons {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-sm);
  margin-top: var(--space-md);
}
 
.state-btn {
  padding: var(--space-md);
  border: 0.125rem solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  min-height: clamp(2.5rem, 5vh, 2.75rem);
}
 
.state-btn:hover {
  background: var(--accent-light);
  border-color: var(--accent-primary);
  color: var(--accent-primary);
}
 
.state-btn.active {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: white;
  box-shadow: var(--shadow-glow);
}
 
/* ============================================================================
   MODULAR GRID SYSTEM
   ============================================================================ */
.dashboard-grid {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: 1fr;
  grid-auto-rows: minmax(min-content, auto);
}
 
@media (min-width: 48rem) {
  .dashboard-grid {
    grid-template-columns: repeat(2, 1fr);
  }
 
  .block-landscape,
  .full-width {
    grid-column: 1 / -1;
  }
 
  .block-square {
    aspect-ratio: 1 / 1;
  }
}
 
@media (min-width: 75rem) {
  .dashboard-grid {
    grid-template-columns: repeat(4, 1fr);
  }
 
  .block-landscape {
    grid-column: span 3;
  }
 
  .block-landscape-wide {
    grid-column: span 4;
  }
 
  .block-square {
    grid-column: span 1;
  }
 
  .block-square-lg {
    grid-column: span 2;
    aspect-ratio: 1 / 1;
  }
}
 
/* ============================================================================
   CARD COMPONENT
   ============================================================================ */
.dashboard-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-glass);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: all 0.3s ease;
}
 
.dashboard-card:hover {
  border-color: var(--glass-border-hover);
  transform: translateY(clamp(-0.125rem, -0.25vw, -0.1875rem));
}
 
.card-header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-lg);
  background: rgba(0, 0, 0, 0.15);
  border-bottom: 1px solid var(--glass-border);
}
 
.card-icon {
  font-size: var(--text-heading);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
 
.card-title {
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 600;
  color: var(--text-primary);
  flex: 1;
  letter-spacing: 0.02em;
}
 
.card-badge {
  font-size: var(--text-micro);
  font-weight: 600;
  padding: var(--space-xs) var(--space-sm);
  background: var(--accent-light);
  color: var(--accent-primary);
  border-radius: var(--radius-sm);
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
 
.card-body {
  padding: var(--space-lg);
  flex: 1;
}
 
.card-footer {
  padding: var(--space-sm) var(--space-lg);
  background: rgba(0, 0, 0, 0.2);
  border-top: 1px solid var(--glass-border);
  font-size: var(--text-micro);
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
 
.card-footer a {
  color: var(--text-secondary);
  transition: color 0.2s ease;
}
 
.card-footer a:hover {
  color: var(--accent-primary);
}
 
@media (min-width: 40rem) {
  .card-footer {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }
}
 
/* ============================================================================
   ALERT FILTERS & ACTIVE ALERTS
   ============================================================================ */
.alert-filter-buttons {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
 
@media (min-width: 40rem) {
  .alert-filter-buttons {
    grid-template-columns: repeat(4, 1fr);
  }
}
 
.alert-filter-btn {
  padding: var(--space-md);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.2);
  color: var(--icon-default);
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s ease;
  min-height: clamp(2.5rem, 5vh, 2.75rem);
}
 
.alert-filter-btn:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--glass-border-hover);
  color: var(--icon-hover);
}
 
.alert-filter-btn.active {
  background: var(--accent-light);
  border-color: var(--accent-primary);
  color: var(--accent-primary);
  box-shadow: var(--shadow-glow);
}
 
.active-alerts-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
  max-height: clamp(20rem, 50vh, 25rem);
  overflow-y: auto;
}
 
.active-alert-item {
  padding: var(--space-md);
  border-left: clamp(0.1875rem, 0.4vw, 0.25rem) solid;
  border-radius: var(--radius-sm);
  transition: all 0.2s ease;
  background: rgba(0, 0, 0, 0.2);
  backdrop-filter: blur(8px);
}
 
.active-alert-item:hover {
  transform: translateX(clamp(0.125rem, 0.5vw, 0.25rem));
  background: rgba(0, 0, 0, 0.3);
}
 
.active-alert-item.severity-extreme {
  background: var(--danger-extreme-bg);
  border-color: var(--danger-extreme);
  box-shadow: var(--danger-extreme-glow);
}
 
.active-alert-item.severity-severe,
.active-alert-item.severity-warning {
  background: var(--danger-warning-bg);
  border-color: var(--danger-warning);
  box-shadow: var(--danger-warning-glow);
}
 
.active-alert-item.severity-moderate,
.active-alert-item.severity-watch {
  background: var(--danger-watch-bg);
  border-color: var(--danger-watch);
  box-shadow: var(--danger-watch-glow);
}
 
.active-alert-item.severity-minor,
.active-alert-item.severity-advisory {
  background: rgba(234, 179, 8, 0.1);
  border-color: var(--danger-watch);
}
 
.active-alert-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
 
.active-alert-type {
  font-weight: 600;
  font-size: var(--text-body);
  flex: 1;
}
 
.active-alert-item.severity-extreme .active-alert-type,
.active-alert-item.severity-severe .active-alert-type,
.active-alert-item.severity-warning .active-alert-type {
  color: var(--danger-warning);
}
 
.active-alert-item.severity-moderate .active-alert-type,
.active-alert-item.severity-watch .active-alert-type {
  color: var(--danger-watch);
}
 
.active-alert-urgency {
  font-size: var(--text-micro);
  font-weight: 600;
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-lg);
  background: rgba(0, 0, 0, 0.2);
  white-space: nowrap;
}
 
.active-alert-headline {
  font-size: var(--text-small);
  color: var(--text-secondary);
  margin-bottom: var(--space-sm);
  line-height: 1.5;
}
 
.active-alert-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  font-size: var(--text-micro);
  color: var(--text-muted);
}
 
.no-active-alerts {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-2xl);
  text-align: center;
}
 
.no-active-alerts-text {
  font-weight: 600;
  color: var(--danger-safe);
  margin-bottom: var(--space-xs);
  font-size: var(--text-heading);
}
 
.no-active-alerts-sub {
  font-size: var(--text-small);
  color: var(--text-muted);
}
 
/* ============================================================================
   INTERACTIVE MAP
   ============================================================================ */
#tribal-map-container {
  position: relative;
  width: 100%;
  height: clamp(20rem, 60vh, 31.25rem);
  min-height: 20rem;
  background: rgba(15, 15, 26, 0.8);
  border-radius: var(--radius-md);
  overflow: hidden;
}
 
@media (min-width: 48rem) {
  #tribal-map-container { height: clamp(25rem, 65vh, 34.375rem); }
}
 
@media (min-width: 64rem) {
  #tribal-map-container { height: clamp(30rem, 70vh, 37.5rem); }
}
 
#tribal-map {
  width: 100%;
  height: 100%;
  z-index: 1;
}
 
/* Map View Controls - Right Side */
.map-view-controls {
  position: absolute;
  top: 50%;
  right: var(--space-md);
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  z-index: 1000;
}
 
.map-view-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: clamp(3rem, 8vw, 3.75rem);
  height: clamp(3rem, 8vw, 3.75rem);
  padding: var(--space-sm);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  color: var(--icon-default);
  cursor: pointer;
  transition: all 0.2s ease;
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 500;
}
 
.map-view-btn:hover {
  background: var(--glass-bg-hover);
  border-color: var(--glass-border-hover);
  color: var(--icon-hover);
}
 
.map-view-btn.active {
  background: var(--accent-light);
  border-color: var(--accent-primary);
  color: var(--accent-primary);
  box-shadow: var(--shadow-glow);
}
 
.map-view-btn svg {
  width: clamp(1rem, 2.5vw, 1.25rem);
  height: clamp(1rem, 2.5vw, 1.25rem);
  margin-bottom: var(--space-xs);
  stroke-width: 1.5;
}
 
/* Center Button */
.map-center-btn {
  position: absolute;
  bottom: clamp(4rem, 10vh, 4.375rem);
  right: var(--space-md);
  width: clamp(2.25rem, 5vw, 2.5rem);
  height: clamp(2.25rem, 5vw, 2.5rem);
  padding: 0;
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  color: var(--icon-default);
  cursor: pointer;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
}
 
.map-center-btn:hover {
  background: var(--glass-bg-hover);
  color: var(--text-primary);
}
 
.map-center-btn svg {
  width: clamp(1rem, 2.5vw, 1.25rem);
  height: clamp(1rem, 2.5vw, 1.25rem);
}
 
/* Map Legend */
.map-legend {
  position: absolute;
  bottom: var(--space-md);
  left: var(--space-md);
  right: clamp(4rem, 12vw, 5rem);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: var(--space-sm) var(--space-md);
  z-index: 1000;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  font-size: var(--text-micro);
  color: var(--text-secondary);
}
 
.legend-item {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}
 
.legend-swatch {
  width: clamp(0.75rem, 1.5vw, 0.875rem);
  height: clamp(0.75rem, 1.5vw, 0.875rem);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
 
.legend-swatch.swatch-warning { background: var(--danger-warning); }
.legend-swatch.swatch-watch { background: var(--danger-watch); }
.legend-swatch.swatch-advisory { background: #F97316; }
.legend-swatch.swatch-radar { background: rgba(0, 255, 100, 0.5); border: 1px solid #0f0; }
.legend-swatch.river-below { background: var(--river-below); }
.legend-swatch.river-normal { background: var(--river-normal); }
.legend-swatch.river-near { background: var(--river-near-flood); }
.legend-swatch.river-flood { background: var(--river-flooding); }
 
.legend-swatch.flood-striped {
  background: repeating-linear-gradient(45deg, var(--danger-warning), var(--danger-warning) 0.125rem, transparent 0.125rem, transparent 0.25rem);
}
 
.legend-swatch.flood-pulse {
  background: var(--danger-warning);
  animation: pulse-legend 1.5s ease-in-out infinite;
}
 
@keyframes pulse-legend {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
 
/* Map Loading Overlay */
.map-loading {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(15, 15, 26, 0.85);
  backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  color: var(--text-secondary);
  gap: var(--space-md);
  transition: opacity 0.3s ease;
}
 
.map-loading.hidden {
  opacity: 0;
  pointer-events: none;
}
 
/* Leaflet Popup Dark Theme */
.leaflet-popup-content-wrapper {
  background: rgba(15, 15, 26, 0.95) !important;
  color: #fff !important;
  border-radius: 0 !important;
  border: 1px solid rgba(255, 255, 255, 0.1) !important;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5) !important;
}
 
.leaflet-popup-tip {
  background: rgba(15, 15, 26, 0.95) !important;
}
 
.leaflet-popup-content {
  margin: 12px 14px !important;
  font-size: 13px !important;
  line-height: 1.4 !important;
  font-family: var(--font-body) !important;
}
 
.popup-header {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
 
.popup-severity-warning { color: #EF4444; }
.popup-severity-watch { color: #FBBF24; }
 
.leaflet-control-zoom {
  margin-bottom: 70px !important;
  margin-right: 12px !important;
}
 
.leaflet-control-zoom a {
  background: rgba(15, 15, 26, 0.9) !important;
  color: rgba(255, 255, 255, 0.8) !important;
  border: 1px solid rgba(255, 255, 255, 0.15) !important;
}
 
.leaflet-control-zoom a:hover {
  background: rgba(30, 30, 50, 0.95) !important;
  color: #fff !important;
}
 
.leaflet-control-attribution {
  display: none !important;
}
 
@media (max-width: 640px) {
  .map-view-controls { right: 8px; }
  .map-view-btn { width: 48px; height: 48px; }
  .map-view-btn span { display: none; }
  .map-legend { right: 56px; padding: 8px 10px; font-size: 10px; gap: 8px; }
}
 
/* ============================================================================
   LOCAL FORECAST
   ============================================================================ */
.local-forecast-grid {
  display: grid;
  gap: var(--space-lg);
  grid-template-columns: 1fr;
}
 
@media (min-width: 768px) {
  .local-forecast-grid {
    grid-template-columns: 1fr 1fr;
  }
}
 
.local-forecast-panel {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  overflow: hidden;
  min-height: 300px;
}
 
.local-forecast-panel-header {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  padding: var(--space-sm) var(--space-md);
  background: rgba(0, 0, 0, 0.3);
  border-bottom: 1px solid var(--glass-border);
  color: var(--text-secondary);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
 
.forecast-period-controls {
  display: flex;
  gap: var(--space-xs);
}
 
.forecast-period-btn {
  padding: 0.25rem 0.625rem;
  font-size: 0.6875rem;
  font-weight: 600;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid var(--glass-border);
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.2s ease;
}
 
.forecast-period-btn:hover {
  background: rgba(255, 255, 255, 0.15);
  color: var(--text-primary);
}
 
/* FIX: was var(--primary-accent) which is undefined; correct token is --accent-primary */
.forecast-period-btn.active {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: #ffffff;
}
 
.qpf-map-container {
  position: relative;
  width: 100%;
  aspect-ratio: 4/3;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.2);
}
 
.qpf-map-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
 
/* Daily Breakdown Panel */
.daily-breakdown-header {
  padding: var(--space-sm) var(--space-md);
  background: rgba(0, 0, 0, 0.2);
}
 
.daily-breakdown-title {
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.125rem;
}
 
.daily-breakdown-location {
  font-size: 0.75rem;
  color: var(--text-muted);
}
 
.daily-breakdown-chart {
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
 
.daily-bar-row {
  display: grid;
  grid-template-columns: 60px 1fr 50px 40px;
  gap: var(--space-sm);
  align-items: center;
}
 
.daily-bar-label {
  font-size: 0.75rem;
  color: var(--text-secondary);
}
 
.daily-bar-day {
  font-weight: 600;
}
 
.daily-bar-date {
  font-size: 0.625rem;
  color: var(--text-muted);
}
 
.daily-bar-track {
  height: 20px;
  background: rgba(0, 0, 0, 0.3);
  overflow: hidden;
  position: relative;
}
 
.daily-bar-fill {
  height: 100%;
  transition: width 0.5s ease;
}
 
.daily-bar-fill.rain-light {
  background: linear-gradient(90deg, #22c55e, #4ade80);
}
 
.daily-bar-fill.rain-moderate {
  background: linear-gradient(90deg, #eab308, #facc15);
}
 
.daily-bar-fill.rain-heavy {
  background: linear-gradient(90deg, #f97316, #fb923c);
}
 
.daily-bar-fill.rain-hazardous {
  background: linear-gradient(90deg, #ef4444, #f87171);
}
 
.daily-bar-amount {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-primary);
  text-align: right;
}
 
.daily-bar-prob {
  font-size: 0.6875rem;
  color: var(--text-muted);
  text-align: right;
}
 
.forecast-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: rgba(0, 0, 0, 0.2);
  border-top: 1px solid var(--glass-border);
}
 
.forecast-legend-item {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.625rem;
  color: var(--text-muted);
}
 
.forecast-legend-color {
  width: 12px;
  height: 12px;
}
 
.forecast-legend-color.light { background: #22c55e; }
.forecast-legend-color.moderate { background: #eab308; }
.forecast-legend-color.heavy { background: #f97316; }
.forecast-legend-color.hazardous { background: #ef4444; }
 
.forecast-totals {
  display: flex;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  background: rgba(0, 0, 0, 0.15);
}
 
.forecast-total-item {
  text-align: center;
  flex: 1;
}
 
.forecast-total-label {
  font-size: 0.625rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
 
.forecast-total-value {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-primary);
}
 
.precip-description {
  font-size: clamp(0.75rem, 2vw, 0.8125rem);
  color: var(--text-secondary);
  margin-bottom: var(--space-md);
  line-height: 1.6;
}
 
/* ============================================================================
   FORECAST SECTION
   ============================================================================ */
.forecast-location {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md);
  background: var(--accent-light);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-md);
}
 
.forecast-location-name {
  font-weight: 600;
  color: var(--accent-primary);
  font-size: clamp(0.875rem, 2vw, 0.9375rem);
}
 
.forecast-grid {
  display: grid;
  gap: var(--space-sm);
}
 
.forecast-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding: var(--space-md);
  background: #f9fafb;
  border-radius: var(--radius-md);
  gap: var(--space-sm);
}
 
@media (min-width: 640px) {
  .forecast-item {
    grid-template-columns: 100px auto 60px 1fr;
  }
}
 
.forecast-period {
  font-weight: 600;
  color: var(--text-primary);
  font-size: clamp(0.8125rem, 2vw, 0.875rem);
}
 
.forecast-temp {
  font-size: clamp(1rem, 3vw, 1.125rem);
  font-weight: 700;
  color: var(--text-primary);
  text-align: center;
}
 
.forecast-precip {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8125rem;
  color: var(--accent-primary);
  font-weight: 600;
  white-space: nowrap;
}
 
.forecast-precip.high { color: var(--severity-warning); }
 
.forecast-desc {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  grid-column: 1 / -1;
  margin-top: 4px;
}
 
@media (min-width: 640px) {
  .forecast-desc { grid-column: auto; margin-top: 0; text-align: right; }
}
 
.forecast-link-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md);
  background: var(--accent-primary);
  color: white;
  text-decoration: none;
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 0.875rem;
  margin-top: var(--space-md);
  transition: all 0.2s ease;
  justify-content: center;
}
 
.forecast-link-btn:hover {
  background: var(--accent-hover);
  transform: translateY(-1px);
}
 
.btn-yellow {
  background: #d4a012;
  color: #1a1a1a;
}
.btn-yellow:hover {
  background: #b8900f;
  color: #1a1a1a;
}
 
.btn-pink {
  background: #9d174d;
  color: #ffffff;
}
.btn-pink:hover {
  background: #831843;
  color: #ffffff;
}
 
.btn-red {
  background: #991b1b;
  color: #ffffff;
}
.btn-red:hover {
  background: #7f1d1d;
  color: #ffffff;
}
 
/* ============================================================================
   RESOURCES
   ============================================================================ */
.resources-grid {
  display: grid;
  gap: var(--space-sm);
  grid-template-columns: repeat(2, 1fr);
}
 
@media (min-width: 640px) {
  .resources-grid { grid-template-columns: repeat(3, 1fr); }
}
 
@media (min-width: 1024px) {
  .resources-grid { grid-template-columns: repeat(4, 1fr); }
}
 
.resource-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-lg);
  background: var(--glass-bg);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--text-primary);
  transition: all 0.2s ease;
  text-align: center;
  min-height: 80px;
  justify-content: center;
  border: 1px solid var(--glass-border);
}
 
.resource-link:hover {
  background: var(--accent-light);
  color: var(--accent-primary);
  transform: translateY(-2px);
  border-color: var(--accent-primary);
}
 
.resource-name {
  font-size: clamp(0.75rem, 2vw, 0.8125rem);
  font-weight: 600;
  line-height: 1.3;
}
 
.resource-link-large {
  grid-column: 1 / -1;
  flex-direction: row;
  justify-content: center;
  gap: var(--space-md);
  padding: var(--space-lg);
  background: var(--accent-primary);
  color: white;
  min-height: 50px;
}
 
.resource-link-large:hover {
  background: var(--accent-hover);
  color: white;
}
 
.resource-link-large .resource-name { font-size: 1rem; }
 
/* ============================================================================
   EMERGENCY CONTACTS
   ============================================================================ */
.emergency-contacts {
  display: grid;
  gap: var(--space-sm);
}
 
.contact-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-md);
  background: var(--glass-bg);
  border-radius: var(--radius-md);
  border: 1px solid var(--glass-border);
  gap: var(--space-md);
}
 
.contact-name {
  font-weight: 600;
  font-size: clamp(0.8125rem, 2vw, 0.875rem);
  color: var(--text-primary);
}
 
.contact-phone {
  font-family: var(--font-mono);
  font-size: clamp(0.8125rem, 2vw, 0.875rem);
  color: var(--accent-primary);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
 
.contact-phone:hover { text-decoration: underline; }
 
.contact-link-large {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--accent-primary);
  color: white;
  text-decoration: none;
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 1rem;
  margin-top: var(--space-md);
  transition: all 0.2s ease;
}
 
.contact-link-large:hover {
  background: var(--accent-hover);
  transform: translateY(-1px);
}
 
/* ============================================================================
   LOADING & ERROR STATES
   ============================================================================ */
.loading-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-xl);
  gap: var(--space-md);
  min-height: 200px;
}
 
.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--card-border);
  border-top-color: var(--accent-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
 
@keyframes spin {
  to { transform: rotate(360deg); }
}
 
.loading-text {
  font-size: clamp(0.8125rem, 2vw, 0.875rem);
  color: var(--text-muted);
  text-align: center;
}
 
.error-state {
  padding: var(--space-lg);
  background: #fef2f2;
  border-radius: var(--radius-md);
  border: 1px solid #fecaca;
  color: #991b1b;
  font-size: clamp(0.8125rem, 2vw, 0.875rem);
  line-height: 1.6;
}
 
.error-state a {
  color: #991b1b;
  font-weight: 600;
}
 
.retry-btn {
  display: inline-block;
  margin-top: var(--space-md);
  padding: 8px 16px;
  cursor: pointer;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--text-primary);
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 0.875rem;
}
 
.retry-btn:hover {
  background: var(--glass-bg-hover);
  border-color: var(--accent-primary);
}
 
/* ============================================================================
   FOOTER
   ============================================================================ */
.dashboard-footer {
  margin-top: var(--space-xl);
  padding: var(--space-lg);
  background: rgba(255,255,255,0.05);
  border-radius: var(--radius-lg);
  text-align: center;
}
 
.footer-sources {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-sm);
  font-size: 0.6875rem;
}
 
.footer-sources a {
  color: rgba(255,255,255,0.6);
  text-decoration: none;
  transition: color 0.2s ease;
}
 
.footer-sources a:hover {
  color: rgba(255,255,255,1);
  text-decoration: underline;
}
 
.footer-sources span {
  color: rgba(255,255,255,0.3);
}
 
/* ============================================================================
   UTILITIES
   ============================================================================ */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
 
@media (hover: none) {
  button, a, .tribe-select {
    -webkit-tap-highlight-color: rgba(8, 145, 178, 0.1);
  }
}
</style>
</head>
<body>
<div class="flood-dashboard" role="main" aria-label="PNW Tribal Dashboard">
 
  <header class="dashboard-header">
    <div class="header-title">
      <h1>PNW Tribal Dashboard</h1>
    </div>
    <p class="header-subtitle">Real-time weather conditions, flood alerts, and forecasts for Pacific Northwest Tribal communities</p>
 
    <div id="main-alert" class="alert-banner status-none" role="alert" aria-live="polite">
      <span class="alert-icon" aria-hidden="true"></span>
      <a class="alert-content alert-link" href="https://www.indigenousaccess.org/alerts" aria-label="Open detailed weather alerts">
        <div class="alert-title" id="alert-title">Loading current conditions...</div>
        <div class="alert-detail" id="alert-detail">Checking alerts for Oregon, Washington, and Idaho</div>
      </a>
    </div>
  </header>
 
  <section class="selector-section" aria-labelledby="selector-heading">
    <label id="selector-heading" class="selector-label" for="tribe-select">
      Select Your Location
    </label>
 
    <select id="tribe-select" class="tribe-select" aria-describedby="selector-heading">
      <option value="">-- Select a Tribal Community --</option>
 
      <optgroup label="Oregon (9 Tribes)">
        <option value="43.5863,-119.0541|Burns Paiute Tribe">Burns Paiute Tribe</option>
        <option value="43.3665,-124.2179|Confederated Tribes of Coos, Lower Umpqua and Siuslaw">Confederated Tribes of Coos, Lower Umpqua and Siuslaw</option>
        <option value="45.0561,-123.6090|Confederated Tribes of Grand Ronde">Confederated Tribes of Grand Ronde</option>
        <option value="44.7212,-123.9212|Confederated Tribes of Siletz Indians">Confederated Tribes of Siletz Indians</option>
        <option value="45.6523,-118.6303|Confederated Tribes of the Umatilla">Confederated Tribes of the Umatilla</option>
        <option value="44.7667,-121.2672|Confederated Tribes of Warm Springs">Confederated Tribes of Warm Springs</option>
        <option value="43.4073,-124.2242|Coquille Indian Tribe">Coquille Indian Tribe</option>
        <option value="43.2234,-123.3417|Cow Creek Band of Umpqua">Cow Creek Band of Umpqua</option>
        <option value="42.5821,-121.8675|Klamath Tribes">Klamath Tribes</option>
      </optgroup>
 
      <optgroup label="Washington (29 Tribes)">
        <option value="46.3776,-120.3080|Yakama Nation">Confederated Tribes and Bands of the Yakama Nation</option>
        <option value="46.8404,-123.2354|Confederated Tribes of Chehalis">Confederated Tribes of the Chehalis Reservation</option>
        <option value="48.1664,-118.9744|Colville Tribes">Confederated Tribes of the Colville Reservation</option>
        <option value="46.1382,-122.9382|Cowlitz Indian Tribe">Cowlitz Indian Tribe</option>
        <option value="47.7629,-124.4314|Hoh Indian Tribe">Hoh Indian Tribe</option>
        <option value="48.0364,-123.0283|Jamestown S'Klallam Tribe">Jamestown S'Klallam Tribe</option>
        <option value="48.3078,-117.2764|Kalispel Indian Community">Kalispel Indian Community</option>
        <option value="48.1184,-123.5573|Lower Elwha Klallam Tribe">Lower Elwha Tribal Community</option>
        <option value="48.8044,-122.6517|Lummi Nation">Lummi Tribe of the Lummi Reservation</option>
        <option value="48.3678,-124.6139|Makah Tribe">Makah Indian Tribe of the Makah Reservation</option>
        <option value="47.2818,-122.1615|Muckleshoot Indian Tribe">Muckleshoot Indian Tribe</option>
        <option value="46.9765,-122.7097|Nisqually Indian Tribe">Nisqually Indian Tribe</option>
        <option value="48.8057,-122.2340|Nooksack Indian Tribe">Nooksack Indian Tribe</option>
        <option value="47.8465,-122.5697|Port Gamble S'Klallam Tribe">Port Gamble S'Klallam Tribe</option>
        <option value="47.2284,-122.4331|Puyallup Tribe">Puyallup Tribe of the Puyallup Reservation</option>
        <option value="47.9082,-124.6348|Quileute Tribe">Quileute Tribe of the Quileute Reservation</option>
        <option value="47.3465,-124.0331|Quinault Indian Nation">Quinault Indian Nation</option>
        <option value="48.5126,-122.6127|Samish Indian Nation">Samish Indian Nation</option>
        <option value="48.2554,-121.6015|Sauk-Suiattle Indian Tribe">Sauk-Suiattle Indian Tribe</option>
        <option value="46.7054,-123.9603|Shoalwater Bay Indian Tribe">Shoalwater Bay Indian Tribe</option>
        <option value="47.3320,-123.1579|Skokomish Indian Tribe">Skokomish Indian Tribe</option>
        <option value="47.5287,-121.8251|Snoqualmie Indian Tribe">Snoqualmie Indian Tribe</option>
        <option value="47.8890,-117.9673|Spokane Tribe">Spokane Tribe of the Spokane Reservation</option>
        <option value="47.2334,-122.9112|Squaxin Island Tribe">Squaxin Island Tribe</option>
        <option value="48.1987,-122.1257|Stillaguamish Tribe">Stillaguamish Tribe of Indians</option>
        <option value="47.7312,-122.5582|Suquamish Tribe">Suquamish Indian Tribe</option>
        <option value="48.4462,-122.5175|Swinomish Indian Tribal Community">Swinomish Indian Tribal Community</option>
        <option value="48.0690,-122.2893|Tulalip Tribes">Tulalip Tribes of Washington</option>
        <option value="48.5184,-122.2329|Upper Skagit Indian Tribe">Upper Skagit Indian Tribe</option>
      </optgroup>
 
      <optgroup label="Idaho (5 Tribes)">
        <option value="47.3343,-116.8881|Coeur d'Alene Tribe">Coeur d'Alene Tribe</option>
        <option value="48.6914,-116.3164|Kootenai Tribe of Idaho">Kootenai Tribe of Idaho</option>
        <option value="46.4046,-116.8047|Nez Perce Tribe">Nez Perce Tribe</option>
        <option value="43.0300,-112.4344|Shoshone-Bannock Tribes">Shoshone-Bannock Tribes</option>
        <option value="41.9517,-116.1092|Shoshone-Paiute Tribes">Shoshone-Paiute Tribes of Duck Valley</option>
      </optgroup>
    </select>
 
    <div class="state-buttons" role="group" aria-label="Filter by state">
      <button type="button" class="state-btn" data-state="OR" aria-pressed="false">Oregon</button>
      <button type="button" class="state-btn" data-state="WA" aria-pressed="false">Washington</button>
      <button type="button" class="state-btn" data-state="ID" aria-pressed="false">Idaho</button>
    </div>
  </section>
 
  <div class="dashboard-grid">
 
    <section class="dashboard-card full-width" aria-labelledby="conditions-heading">
      <div class="card-header">
        <h2 class="card-title" id="conditions-heading">Current Conditions and Forecast</h2>
        <span class="card-badge">LIVE</span>
      </div>
      <div class="card-body">
        <div id="tribal-map-container">
          <div id="tribal-map"></div>
 
          <!-- ADDED: map view controls (CSS and JS already supported these but the markup was missing) -->
          <div class="map-view-controls" role="group" aria-label="Switch map view">
            <button type="button" class="map-view-btn active" data-view="current" aria-pressed="true" title="Current conditions and radar">
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
                <path stroke-linecap="round" stroke-linejoin="round" d="M3 15a4 4 0 014-4 5 5 0 019.584-1.32A4.5 4.5 0 1118 19H7a4 4 0 01-4-4z"/>
              </svg>
              <span>Current</span>
            </button>
            <button type="button" class="map-view-btn" data-view="forecast" aria-pressed="false" title="3-day precipitation forecast">
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
                <path stroke-linecap="round" stroke-linejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
              </svg>
              <span>Forecast</span>
            </button>
            <button type="button" class="map-view-btn" data-view="flooding" aria-pressed="false" title="River gauges and flooding">
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
                <path stroke-linecap="round" stroke-linejoin="round" d="M3 12c2 0 2-2 4-2s2 2 4 2 2-2 4-2 2 2 4 2M3 18c2 0 2-2 4-2s2 2 4 2 2-2 4-2 2 2 4 2M3 6c2 0 2-2 4-2s2 2 4 2 2-2 4-2 2 2 4 2"/>
              </svg>
              <span>Flooding</span>
            </button>
          </div>
 
          <button type="button" class="map-center-btn" title="Reset View">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
            </svg>
          </button>
 
          <div class="map-legend" id="map-legend">
            <div class="legend-item">
              <span class="legend-swatch swatch-warning"></span>
              <span>Warning</span>
            </div>
            <div class="legend-item">
              <span class="legend-swatch swatch-watch"></span>
              <span>Watch</span>
            </div>
            <div class="legend-item">
              <span class="legend-swatch swatch-advisory"></span>
              <span>Advisory</span>
            </div>
            <div class="legend-item">
              <span class="legend-swatch swatch-radar"></span>
              <span>Radar</span>
            </div>
          </div>
 
          <div class="map-loading" id="map-loading">
            <div class="loading-spinner"></div>
            <span>Loading map...</span>
          </div>
        </div>
      </div>
      <div class="card-footer">
        <span>Sources: <a href="https://www.weather.gov" target="_blank" rel="noopener" style="color:inherit;">NWS</a>, <a href="https://waterdata.usgs.gov" target="_blank" rel="noopener" style="color:inherit;">USGS</a>, <a href="https://msc.fema.gov/portal/home" target="_blank" rel="noopener" style="color:inherit;">FEMA NFHL</a></span>
        <span>Live Updates</span>
      </div>
    </section>
 
    <section id="local-forecast-section" class="dashboard-card full-width forecast-container" aria-labelledby="forecast-heading">
      <div class="card-header">
        <h2 class="card-title" id="forecast-heading">7-Day Forecast</h2>
        <span class="card-badge">Local</span>
      </div>
      <div class="card-body">
        <div class="forecast-location">
          <span id="forecast-location-name">Select a Tribe above</span>
        </div>
        <div id="forecast-content" class="forecast-grid">
          <p class="precip-description">Select a Tribal community above to view the local 7-day weather forecast.</p>
        </div>
      </div>
      <div class="card-footer">
        <span>Source: <a href="https://www.weather.gov" target="_blank" rel="noopener">National Weather Service</a></span>
        <span id="forecast-updated">--</span>
      </div>
    </section>
 
    <section class="dashboard-card full-width" aria-labelledby="hazard-alerts-heading">
      <div class="card-header">
        <h2 class="card-title" id="hazard-alerts-heading">Active Warnings and Hazards</h2>
        <span class="card-badge" id="active-alerts-count">Loading...</span>
      </div>
      <div class="card-body">
        <div class="alert-filter-buttons" role="group" aria-label="Filter alerts by type">
          <button type="button" class="alert-filter-btn active" data-filter="all" aria-pressed="true">
            All Warnings
          </button>
          <button type="button" class="alert-filter-btn" data-filter="flood" aria-pressed="false">
            Flood
          </button>
          <button type="button" class="alert-filter-btn" data-filter="wind" aria-pressed="false">
            Wind/Gale
          </button>
          <button type="button" class="alert-filter-btn" data-filter="snow" aria-pressed="false">
            Snow/Blizzard
          </button>
        </div>
 
        <div id="active-alerts-content" class="active-alerts-list">
          <div class="loading-state">
            <div class="loading-spinner"></div>
            <span class="loading-text">Loading active warnings from NWS...</span>
          </div>
        </div>
 
        <a href="https://www.indigenousaccess.org/alerts" class="forecast-link-btn btn-yellow">
          Detailed Alerts and Safety
        </a>
      </div>
      <div class="card-footer">
        <span>Source: <a href="https://www.weather.gov" target="_blank" rel="noopener">National Weather Service</a></span>
        <span id="active-alerts-updated">--</span>
      </div>
    </section>
 
    <section class="dashboard-card full-width" aria-labelledby="local-forecast-heading">
      <div class="card-header">
        <h2 class="card-title" id="local-forecast-heading">Local Forecast</h2>
        <span class="card-badge">QPF</span>
      </div>
      <div class="card-body">
        <div class="local-forecast-grid">
          <div class="local-forecast-panel">
            <div class="local-forecast-panel-header">
              <span>Precipitation Forecast Map</span>
              <div class="forecast-period-controls">
                <button class="forecast-period-btn active" data-period="today">Today</button>
                <button class="forecast-period-btn" data-period="3day">3-Day</button>
                <button class="forecast-period-btn" data-period="7day">7-Day</button>
              </div>
            </div>
            <div class="qpf-map-container">
              <img
                id="qpf-map-image"
                src="https://www.nwrfc.noaa.gov/images/nwrfc/obs/fcstprecipday1.png"
                alt="Northwest precipitation forecast map"
                class="qpf-map-image"
                loading="lazy"
              >
            </div>
          </div>
 
          <div class="local-forecast-panel">
            <div class="daily-breakdown-header">
              <div class="daily-breakdown-title">Daily Breakdown</div>
              <div class="daily-breakdown-location" id="forecast-location-label">Pacific Northwest</div>
            </div>
            <div class="daily-breakdown-chart" id="daily-breakdown-chart">
              </div>
            <div class="forecast-legend">
              <div class="forecast-legend-item">
                <div class="forecast-legend-color light"></div>
                <span>Light (<2")</span>
              </div>
              <div class="forecast-legend-item">
                <div class="forecast-legend-color moderate"></div>
                <span>Moderate (2-5")</span>
              </div>
              <div class="forecast-legend-item">
                <div class="forecast-legend-color heavy"></div>
                <span>Heavy (5-10")</span>
              </div>
              <div class="forecast-legend-item">
                <div class="forecast-legend-color hazardous"></div>
                <span>Hazardous (>10")</span>
              </div>
            </div>
            <div class="forecast-totals" id="forecast-totals">
              </div>
          </div>
        </div>
      </div>
      <div class="card-footer">
        <span>Source: <a href="https://www.wpc.ncep.noaa.gov" target="_blank" rel="noopener">NOAA WPC</a></span>
        <span>Updates every 6 hours</span>
      </div>
    </section>
 
    <section class="dashboard-card" aria-labelledby="resources-heading">
      <div class="card-header">
        <h2 class="card-title" id="resources-heading">Quick Resources</h2>
      </div>
      <div class="card-body">
        <div class="resources-grid">
          <a href="https://www.indigenousaccess.org/home" class="resource-link resource-link-large btn-pink">
            <span class="resource-name">View All Resources</span>
          </a>
          <a href="https://www.weather.gov/safety/flood" target="_blank" rel="noopener" class="resource-link">
            <span class="resource-name">Flood Safety</span>
          </a>
          <a href="https://www.ready.gov/floods" target="_blank" rel="noopener" class="resource-link">
            <span class="resource-name">Preparedness</span>
          </a>
          <a href="https://www.disasterassistance.gov/" target="_blank" rel="noopener" class="resource-link">
            <span class="resource-name">FEMA Aid</span>
          </a>
        </div>
      </div>
    </section>
 
    <section class="dashboard-card" aria-labelledby="contacts-heading">
      <div class="card-header">
        <h2 class="card-title" id="contacts-heading">Emergency Contacts</h2>
      </div>
      <div class="card-body">
        <div class="emergency-contacts">
          <div class="contact-item">
            <span class="contact-name">Emergency Services</span>
            <a href="tel:911" class="contact-phone">911</a>
          </div>
          <div class="contact-item">
            <span class="contact-name">FEMA Helpline</span>
            <a href="tel:1-800-621-3362" class="contact-phone">1-800-621-3362</a>
          </div>
          <div class="contact-item">
            <span class="contact-name">NWS Seattle</span>
            <a href="tel:206-526-6087" class="contact-phone">206-526-6087</a>
          </div>
          <div class="contact-item">
            <span class="contact-name">NWS Portland</span>
            <a href="tel:503-261-9246" class="contact-phone">503-261-9246</a>
          </div>
        </div>
 
        <a href="https://www.indigenousaccess.org/contacts" class="contact-link-large btn-red">
          View All Emergency Contacts
        </a>
      </div>
    </section>
 
  </div><footer class="dashboard-footer">
    <div class="footer-sources">
      <a href="https://www.weather.gov" target="_blank" rel="noopener">NOAA/NWS</a>
      <span>|</span>
      <a href="https://waterdata.usgs.gov" target="_blank" rel="noopener">USGS</a>
      <span>|</span>
      <a href="https://msc.fema.gov/portal/home" target="_blank" rel="noopener">FEMA NFHL</a>
      <span>|</span>
      <a href="https://www.wpc.ncep.noaa.gov" target="_blank" rel="noopener">NOAA WPC</a>
      <span>|</span>
      <a href="https://leafletjs.com" target="_blank" rel="noopener">Leaflet</a>
      <span>|</span>
      <a href="https://carto.com" target="_blank" rel="noopener">CARTO</a>
      <span>|</span>
      <a href="https://mesonet.agron.iastate.edu" target="_blank" rel="noopener">Iowa Environmental Mesonet</a>
      <span>|</span>
      <span style="color: rgba(255,255,255,0.4);">Tribal data: BIA Federal Register 89 FR 944 (Jan 2024)</span>
    </div>
  </footer>
 
</div><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
 
<script>
(function() {
  'use strict';
 
  // ============================================================================
  // CONFIGURATION
  // ============================================================================
  const CONFIG = {
    USER_AGENT: 'IndigenousAccess-TribalDashboard/2.0 (indigenousaccess.org)',
    REFRESH_INTERVAL: 60000,
 
    PNW_CENTER: [47.5, -122.0],
    DEFAULT_ZOOM: 6,
    MIN_ZOOM: 4,
    MAX_ZOOM: 12,
 
    API_ENDPOINTS: {
      NWS_ALERTS: 'https://api.weather.gov/alerts/active',
      NWS_POINTS: 'https://api.weather.gov/points',
      USGS_WATER: 'https://waterservices.usgs.gov/nwis/iv/',
      FEMA_NFHL: 'https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer',
      TRIBAL_BOUNDARIES: 'https://atniclimate.github.io/maps/data/tribal-boundaries/pnw-tribal-boundaries-simplified.geojson',
      TRIBAL_BOUNDARIES_FULL: 'https://atniclimate.github.io/maps/data/tribal-boundaries/pnw-tribal-boundaries.geojson',
      ROAD_CLOSURES: null
    },
 
    DARK_TILE_URL: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
    RADAR_TILE_URL: 'https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q/{z}/{x}/{y}.png',
    QPF_TILE_URL: 'https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/q2-p72h/{z}/{x}/{y}.png',
 
    ALERT_CATEGORIES: {
      flood: ['Flood', 'Flash Flood', 'Coastal Flood', 'River Flood'],
      wind: ['Gale', 'Wind', 'Hurricane', 'Tropical Storm', 'High Wind'],
      snow: ['Snow', 'Blizzard', 'Ice', 'Winter Storm', 'Freeze', 'Frost', 'Cold', 'Wind Chill', 'Avalanche']
    },
 
    RIVER_COLORS: {
      below_normal: '#8B4513',
      normal: '#22C55E',
      action: '#84CC16',
      near_flood: '#F97316',
      flooding: '#EF4444'
    },
 
    SEVERITY_COLORS: {
      EMERGENCY: '#7C2D12',
      WARNING: '#EF4444',
      WATCH: '#FBBF24',
      ADVISORY: '#F97316',
      STATEMENT: '#6B7280'
    },
 
    FLOOD_THRESHOLDS: {
      FLOODING: 20,
      NEAR_FLOOD: 15,
      ACTION: 10,
      NORMAL: 5
    },
 
    FETCH_TIMEOUT: 15000,
    RADAR_REFRESH_INTERVAL: 120000
  };
 
  const PNW_RIVER_GAUGES = [
    '12048000', '12061500', '12041200', '12039500',
    '12433000', '14105700', '14211720', '12113000',
    '12189500', '14321000', '13317000', '12149000'
  ];
 
  // ============================================================================
  // STATE
  // ============================================================================
  let currentAlerts = [];
  let currentFilter = 'all';
  let map = null;
  let currentMapView = 'current';
  let layers = {
    radar: null,
    forecast: null,
    alerts: null,
    rivers: null,
    floodZones: null,
    tribalBoundaries: null,
    roadClosures: null
  };
  let cachedData = {
    alerts: [],
    rivers: [],
    lastAlertUpdate: null,
    lastRiverUpdate: null
  };
 
  let domCache = {};
 
  let intervals = {
    alertRefresh: null,
    radarRefresh: null
  };
 
  // FIX: prevent double-initialization in Squarespace where mercury:load + DOMContentLoaded both fire
  let isInitialized = false;
 
  // ============================================================================
  // UTILITY FUNCTIONS
  // ============================================================================
 
  /**
   * Fetch with timeout - prevents indefinite waiting on slow APIs
   */
  async function fetchWithTimeout(url, options = {}, timeoutMs = CONFIG.FETCH_TIMEOUT) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
 
    try {
      const response = await fetch(url, {
        ...options,
        signal: controller.signal
      });
      clearTimeout(timeoutId);
      return response;
    } catch (error) {
      clearTimeout(timeoutId);
      if (error.name === 'AbortError') {
        throw new Error(`Request timed out after ${timeoutMs / 1000}s: ${url}`);
      }
      throw error;
    }
  }
 
  function cacheDOMElements() {
    domCache = {
      alertsContent: document.getElementById('active-alerts-content'),
      alertsCount: document.getElementById('active-alerts-count'),
      alertsUpdated: document.getElementById('active-alerts-updated'),
      mainAlert: document.getElementById('main-alert'),
      alertTitle: document.getElementById('alert-title'),
      alertDetail: document.getElementById('alert-detail'),
      mapLoading: document.getElementById('map-loading'),
      tribeSelect: document.getElementById('tribe-select'),
      forecastSection: document.getElementById('local-forecast-section'),
      forecastContent: document.getElementById('forecast-content'),
      forecastLocationName: document.getElementById('forecast-location-name'),
      forecastUpdated: document.getElementById('forecast-updated'),
      qpfMapImage: document.getElementById('qpf-map-image'),
      dailyBreakdownChart: document.getElementById('daily-breakdown-chart'),
      forecastTotals: document.getElementById('forecast-totals'),
      forecastLocationLabel: document.getElementById('forecast-location-label')
    };
  }
 
  function getElement(key) {
    if (!domCache[key]) {
      console.warn(`DOM element not cached: ${key}`);
      return document.getElementById(key.replace(/([A-Z])/g, '-$1').toLowerCase());
    }
    return domCache[key];
  }
 
  function formatTime(dateString) {
    if (!dateString) {
      console.warn('formatTime called with empty dateString');
      return 'Time unavailable';
    }
    try {
      const date = new Date(dateString);
      if (isNaN(date.getTime())) {
        console.warn('formatTime: Invalid date string:', dateString);
        return 'Invalid time';
      }
      return date.toLocaleString('en-US', {
        month: 'short', day: 'numeric',
        hour: 'numeric', minute: '2-digit', hour12: true
      });
    } catch (e) {
      console.error('formatTime error:', e, 'Input:', dateString);
      return 'Time error';
    }
  }
 
  function truncate(str, maxLength) {
    if (!str) return '';
    return str.length > maxLength ? str.substring(0, maxLength) + '...' : str;
  }
 
  function getAlertCategory(event) {
    const eventLower = (event || '').toLowerCase();
    for (const [category, keywords] of Object.entries(CONFIG.ALERT_CATEGORIES)) {
      if (keywords.some(keyword => eventLower.includes(keyword.toLowerCase()))) {
        return category;
      }
    }
    return 'other';
  }
 
  function isWarningOrAlert(alert) {
    const event = (alert.properties?.event || '').toLowerCase();
    const severity = (alert.properties?.severity || '').toLowerCase();
    return event.includes('warning') ||
           severity === 'severe' ||
           severity === 'extreme' ||
           event.includes('emergency');
  }
 
  function getAlertSeverityClass(severity) {
    const sev = (severity || '').toLowerCase();
    if (sev === 'extreme') return 'severity-extreme';
    if (sev === 'severe') return 'severity-severe';
    if (sev === 'moderate') return 'severity-moderate';
    if (sev === 'minor') return 'severity-minor';
    return 'severity-warning';
  }
 
  function mapSeverity(nwsSeverity, urgency, event) {
    const emergencyEvents = ['Tsunami Warning', 'Earthquake Warning', 'Tornado Warning'];
    const warningEvents = ['High Wind Warning', 'Winter Storm Warning', 'Flood Warning', 'Flash Flood Warning', 'Blizzard Warning'];
 
    if (emergencyEvents.some(e => event?.includes(e)) || nwsSeverity === 'Extreme' || urgency === 'Immediate') {
      return 'EMERGENCY';
    }
    if (warningEvents.some(e => event?.includes(e)) || nwsSeverity === 'Severe') {
      return 'WARNING';
    }
    if (event?.includes('Watch') || nwsSeverity === 'Moderate') {
      return 'WATCH';
    }
    if (event?.includes('Advisory')) {
      return 'ADVISORY';
    }
    return 'STATEMENT';
  }
 
  function getRiverFloodStatus(level) {
    if (!level) return 'normal';
    const { FLOODING, NEAR_FLOOD, ACTION, NORMAL } = CONFIG.FLOOD_THRESHOLDS;
    if (level > FLOODING) return 'flooding';
    if (level > NEAR_FLOOD) return 'near_flood';
    if (level > ACTION) return 'action';
    if (level > NORMAL) return 'normal';
    return 'below_normal';
  }
 
  // ============================================================================
  // ACTIVE ALERTS FETCHING & DISPLAY
  // ============================================================================
  async function fetchActiveAlerts() {
    const alertsContent = domCache.alertsContent || document.getElementById('active-alerts-content');
    const alertsCount = domCache.alertsCount || document.getElementById('active-alerts-count');
    const alertsUpdated = domCache.alertsUpdated || document.getElementById('active-alerts-updated');
    const mainAlert = domCache.mainAlert || document.getElementById('main-alert');
    const alertTitle = domCache.alertTitle || document.getElementById('alert-title');
    const alertDetail = domCache.alertDetail || document.getElementById('alert-detail');
 
    try {
      const url = `${CONFIG.API_ENDPOINTS.NWS_ALERTS}?area=OR,WA,ID&status=actual&message_type=alert`;
      const response = await fetchWithTimeout(url);
 
      if (!response.ok) throw new Error(`NWS API returned HTTP ${response.status}`);
 
      const data = await response.json();
      currentAlerts = data.features || [];
      cachedData.alerts = currentAlerts;
      cachedData.lastAlertUpdate = new Date();
 
      alertsUpdated.textContent = `Updated: ${formatTime(new Date().toISOString())}`;
 
      // FIX: clear any error styling from a prior failure
      if (alertsCount && alertsCount.style) {
        alertsCount.style.background = '';
      }
 
      const warningsOnly = currentAlerts.filter(isWarningOrAlert);
 
      if (warningsOnly.length > 0) {
        alertsCount.textContent = warningsOnly.length;
 
        const hasExtreme = warningsOnly.some(a => a.properties.severity === 'Extreme');
        const hasSevere = warningsOnly.some(a => a.properties.severity === 'Severe');
 
        if (hasExtreme) {
          mainAlert.className = 'alert-banner status-warning';
          alertTitle.textContent = 'EXTREME WEATHER WARNING';
          alertDetail.textContent = 'Life-threatening conditions exist. Take immediate action.';
        } else if (hasSevere) {
          mainAlert.className = 'alert-banner status-warning';
          alertTitle.textContent = `${warningsOnly.length} Active Warning${warningsOnly.length > 1 ? 's' : ''}`;
          alertDetail.textContent = 'Hazardous conditions reported. Review warnings below.';
        } else {
          mainAlert.className = 'alert-banner status-watch';
          alertTitle.textContent = `${warningsOnly.length} Active Warning${warningsOnly.length > 1 ? 's' : ''}`;
          alertDetail.textContent = 'Weather warnings in effect. Stay informed.';
        }
 
        displayAlerts(currentFilter);
 
      } else {
        alertsCount.textContent = '0';
        mainAlert.className = 'alert-banner status-none';
        alertTitle.textContent = 'No Active Weather Warnings';
        alertDetail.textContent = 'No warnings for Oregon, Washington, or Idaho.';
 
        alertsContent.innerHTML = `
          <div class="no-active-alerts">
            <p class="no-active-alerts-text">No Active Warnings</p>
            <p class="no-active-alerts-sub">Oregon, Washington, and Idaho</p>
          </div>
        `;
      }
 
      if (map && layers.alerts) {
        renderMapAlerts(currentAlerts);
      }
 
    } catch (error) {
      console.error('Alert fetch error:', error);
 
      const isTimeout = error.message?.includes('timed out');
      const isNetworkError = error.message?.includes('Failed to fetch') || error.name === 'TypeError';
      const isServerError = error.message?.includes('HTTP 5');
 
      let userMessage = 'Unable to load weather alerts. ';
      if (isTimeout) {
        userMessage += 'The NWS server is responding slowly. ';
      } else if (isNetworkError) {
        userMessage += 'Please check your internet connection. ';
      } else if (isServerError) {
        userMessage += 'The NWS service is experiencing issues. ';
      }
 
      // FIX: replaced inline onclick (which referenced an IIFE-scoped function and would
      // throw ReferenceError) with a class-based button bound via event delegation below
      alertsContent.innerHTML = `
        <div class="error-state">
          <strong>⚠️ Alert Data Unavailable</strong><br>
          ${userMessage}<br><br>
          <a href="https://www.weather.gov/alerts" target="_blank" rel="noopener" style="color: var(--accent-primary);">
            View alerts at weather.gov →
          </a>
          <br>
          <button type="button" class="retry-btn" data-retry="alerts">Retry</button>
        </div>
      `;
      alertsCount.textContent = 'Error';
      if (alertsCount.style) alertsCount.style.background = 'var(--danger-warning-bg)';
    }
  }
 
  function displayAlerts(filter) {
    const alertsContent = domCache.alertsContent || document.getElementById('active-alerts-content');
 
    let filteredAlerts = currentAlerts.filter(isWarningOrAlert);
 
    if (filter !== 'all') {
      filteredAlerts = filteredAlerts.filter(alert => {
        return getAlertCategory(alert.properties.event) === filter;
      });
    }
 
    if (filteredAlerts.length === 0) {
      alertsContent.innerHTML = `
        <div class="no-active-alerts">
          <p class="no-active-alerts-text">No warnings in this category</p>
          <p class="no-active-alerts-sub">Try a different filter or view all warnings</p>
        </div>
      `;
      return;
    }
 
    let html = '';
    filteredAlerts.forEach(alert => {
      const props = alert.properties;
      const severityClass = getAlertSeverityClass(props.severity);
      const urgency = props.urgency || 'Unknown';
 
      html += `
        <div class="active-alert-item ${severityClass}">
          <div class="active-alert-header">
            <span class="active-alert-type">${props.event || 'Weather Warning'}</span>
            <span class="active-alert-urgency">${urgency}</span>
          </div>
          <p class="active-alert-headline">${truncate(props.headline || props.description || 'No details available', 200)}</p>
          <div class="active-alert-meta">
            <span>${truncate(props.areaDesc || 'Unknown area', 60)}</span>
            <span>Expires: ${formatTime(props.expires)}</span>
          </div>
        </div>
      `;
    });
 
    alertsContent.innerHTML = html;
  }
 
  // ============================================================================
  // MAP INITIALIZATION
  // ============================================================================
  function initMap() {
    if (typeof L === 'undefined') {
      console.error('Leaflet not loaded');
      const mapLoading = document.getElementById('map-loading');
      if (mapLoading) {
        mapLoading.innerHTML = `
          <div class="error-state" style="margin: 20px;">
            <strong>⚠️ Map Service Unavailable</strong><br>
            Failed to load the map library. Please check your network connection and refresh the page.
          </div>
        `;
      }
      return;
    }
 
    layers.alerts = L.layerGroup();
    layers.rivers = L.layerGroup();
    layers.floodZones = L.layerGroup();
    layers.tribalBoundaries = L.layerGroup();
    layers.roadClosures = L.layerGroup();
 
    map = L.map('tribal-map', {
      center: CONFIG.PNW_CENTER,
      zoom: CONFIG.DEFAULT_ZOOM,
      minZoom: CONFIG.MIN_ZOOM,
      maxZoom: CONFIG.MAX_ZOOM,
      zoomControl: true,
      scrollWheelZoom: false
    });
 
    L.tileLayer(CONFIG.DARK_TILE_URL, {
      attribution: '© <a href="https://carto.com/">CARTO</a>',
      subdomains: 'abcd'
    }).addTo(map);
 
    layers.tribalBoundaries.addTo(map);
    layers.roadClosures.addTo(map);
    layers.alerts.addTo(map);
    layers.rivers.addTo(map);
 
    loadTribalBoundaries();
    loadRoadClosures();
 
    window.dashboardMap = map;
 
    loadMapView('current');
 
    document.getElementById('map-loading').classList.add('hidden');
 
    bindMapControls();
  }
 
  function bindMapControls() {
    document.querySelectorAll('.map-view-btn').forEach(btn => {
      btn.addEventListener('click', function() {
        const view = this.dataset.view;
        if (view !== currentMapView) {
          document.querySelectorAll('.map-view-btn').forEach(b => {
            b.classList.remove('active');
            b.setAttribute('aria-pressed', 'false');
          });
          this.classList.add('active');
          this.setAttribute('aria-pressed', 'true');
          currentMapView = view;
          loadMapView(view);
          updateMapLegend(view);
        }
      });
    });
 
    const centerBtn = document.querySelector('.map-center-btn');
    if (centerBtn) {
      centerBtn.addEventListener('click', function() {
        map.flyTo(CONFIG.PNW_CENTER, CONFIG.DEFAULT_ZOOM, { duration: 0.5 });
      });
    }
  }
 
  async function loadMapView(view) {
    const mapLoading = domCache.mapLoading || document.getElementById('map-loading');
    if (mapLoading) mapLoading.classList.remove('hidden');
 
    try {
      switch(view) {
        case 'current':
          if (layers.forecast) map.removeLayer(layers.forecast);
          loadRadarOverlay();
          if (cachedData.alerts.length > 0) {
            renderMapAlerts(cachedData.alerts);
          }
          if (layers.floodZones) map.removeLayer(layers.floodZones);
          break;
 
        case 'forecast':
          if (layers.radar) map.removeLayer(layers.radar);
          loadForecastOverlay();
          if (cachedData.alerts.length > 0) {
            renderMapAlerts(cachedData.alerts);
          }
          if (layers.floodZones) map.removeLayer(layers.floodZones);
          break;
 
        case 'flooding':
          if (layers.radar) map.removeLayer(layers.radar);
          if (layers.forecast) map.removeLayer(layers.forecast);
          await loadRiverGauges();
          if (layers.floodZones) layers.floodZones.addTo(map);
          break;
      }
    } catch (error) {
      console.error('Error loading map view:', error);
      if (mapLoading) {
        // FIX: replaced inline onclick (IIFE-scoped function reference) with class-based retry button
        mapLoading.innerHTML = `
          <div style="color: var(--danger-warning); text-align: center; padding: 20px;">
            <strong>⚠️ Map View Failed to Load</strong><br>
            Unable to display ${view} view.<br><br>
            <button type="button" class="retry-btn" data-retry="mapview" data-view="${view}">Retry</button>
          </div>
        `;
      }
      return;
    }
    if (mapLoading) mapLoading.classList.add('hidden');
  }
 
  function loadRadarOverlay() {
    if (layers.radar) {
      map.removeLayer(layers.radar);
    }
    layers.radar = L.tileLayer(CONFIG.RADAR_TILE_URL, {
      opacity: 0.6,
      attribution: 'Radar: IEM'
    }).addTo(map);
  }
 
  function loadForecastOverlay() {
    if (layers.forecast) {
      map.removeLayer(layers.forecast);
    }
    layers.forecast = L.tileLayer(CONFIG.QPF_TILE_URL, {
      opacity: 0.7,
      attribution: 'Forecast: IEM/NWS'
    }).addTo(map);
  }
 
  async function loadTribalBoundaries() {
    try {
      const response = await fetchWithTimeout(CONFIG.API_ENDPOINTS.TRIBAL_BOUNDARIES, {}, 15000);
 
      if (!response.ok) {
        throw new Error(`Tribal boundaries fetch error: ${response.status}`);
      }
 
      const geojson = await response.json();
 
      if(layers.tribalBoundaries) layers.tribalBoundaries.clearLayers();
 
      const boundaryLayer = L.geoJSON(geojson, {
        style: function(feature) {
          return {
            color: '#9B59B6',
            weight: 2,
            opacity: 0.8,
            fillColor: '#9B59B6',
            fillOpacity: 0.15,
            dashArray: '5, 5'
          };
        },
        onEachFeature: function(feature, layer) {
          const props = feature.properties;
          if (props && props.name) {
            layer.bindPopup(`
              <div style="font-family: inherit; min-width: 150px;">
                <strong style="color: #FFD700; font-size: 1.1em;">${props.name}</strong>
                ${props.state ? `<br><span style="color: #9aa8b8;">State: ${props.state}</span>` : ''}
                ${props.acres ? `<br><span style="color: #9aa8b8;">Area: ${Number(props.acres).toLocaleString()} acres</span>` : ''}
                ${props.classification ? `<br><span style="color: #9aa8b8;">Classification: ${props.classification}</span>` : ''}
              </div>
            `);
            layer.bindTooltip(props.name, {
              permanent: false,
              direction: 'center',
              className: 'tribal-tooltip'
            });
          }
        }
      });
 
      layers.tribalBoundaries.addLayer(boundaryLayer);
      console.log(`Loaded ${geojson.features?.length || 0} Tribal boundary features from GitHub Pages`);
 
    } catch (error) {
      console.error('Failed to load Tribal boundaries:', error);
      const mapContainer = document.getElementById('tribal-map-container');
      if (mapContainer && !document.getElementById('tribal-boundary-notice')) {
        const notice = document.createElement('div');
        notice.id = 'tribal-boundary-notice';
        notice.innerHTML = `
          <div style="position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1000; background: rgba(30,40,50,0.95); padding: 8px 16px; border-radius: 6px; border: 1px solid #444; font-size: 0.85rem;">
            ⚠️ Tribal boundary data unavailable
            <a href="https://biamaps.geoplatform.gov/" target="_blank" style="color: #FFD700; margin-left: 8px;">View at BIA →</a>
            <button type="button" class="dismiss-notice-btn" style="background: none; border: none; color: #888; margin-left: 8px; cursor: pointer;">✕</button>
          </div>
        `;
        mapContainer.style.position = 'relative';
        mapContainer.appendChild(notice);
 
        // FIX: replaced inline onclick with proper listener (inline handlers fail under strict CSPs)
        const dismissBtn = notice.querySelector('.dismiss-notice-btn');
        if (dismissBtn) {
          dismissBtn.addEventListener('click', function() {
            notice.remove();
          });
        }
      }
    }
  }
 
  async function loadRoadClosures() {
    const knownClosures = [
      {
        id: 'wa-sr20-north-cascades',
        road: 'SR 20 - North Cascades Highway',
        status: 'full',
        reason: 'Seasonal closure (Nov-May) - Snow/avalanche',
        seasonal: true,
        route: [
          [48.7319, -121.0675], [48.7450, -121.0200], [48.7550, -120.9500],
          [48.7600, -120.8800], [48.7550, -120.8100], [48.7400, -120.7400],
          [48.7200, -120.6800], [48.6900, -120.6200], [48.6600, -120.5500],
          [48.6300, -120.5000], [48.5950, -120.4500]
        ]
      },
      {
        id: 'wa-sr410-chinook',
        road: 'SR 410 - Chinook Pass',
        status: 'full',
        reason: 'Seasonal closure (Nov-May) - Snow conditions',
        seasonal: true,
        route: [
          [46.9150, -121.5500], [46.8950, -121.5350], [46.8750, -121.5200],
          [46.8550, -121.4900], [46.8350, -121.4600], [46.8150, -121.4300]
        ]
      },
      {
        id: 'wa-sr542-mt-baker',
        road: 'SR 542 - Mt. Baker Highway',
        status: 'partial',
        reason: 'Seasonal closure beyond ski area (Oct-Jul)',
        seasonal: true,
        route: [
          [48.8615, -121.6790], [48.8550, -121.6850], [48.8480, -121.6900],
          [48.8420, -121.6950], [48.8350, -121.7020], [48.8285, -121.7094]
        ]
      },
      {
        id: 'or-mckenzie-pass',
        road: 'OR 242 - McKenzie Pass',
        status: 'full',
        reason: 'Seasonal closure (Nov-Jun) - Snow',
        seasonal: true,
        route: [
          [44.2800, -121.9500], [44.2700, -121.9200], [44.2600, -121.8800],
          [44.2567, -121.8412], [44.2450, -121.8000], [44.2300, -121.7600]
        ]
      },
      {
        id: 'wa-sr123-cayuse',
        road: 'SR 123 - Cayuse Pass',
        status: 'full',
        reason: 'Seasonal closure (Nov-May) - Snow conditions',
        seasonal: true,
        route: [
          [46.9100, -121.5100], [46.8950, -121.5200], [46.8800, -121.5350],
          [46.8650, -121.5500], [46.8500, -121.5650]
        ]
      },
      {
        id: 'id-lolo-pass',
        road: 'US 12 - Lolo Pass',
        status: 'partial',
        reason: 'Chain requirements - Winter weather',
        seasonal: false,
        route: [
          [46.6500, -114.5200], [46.6450, -114.5400], [46.6400, -114.5600],
          [46.6334, -114.5823], [46.6250, -114.6100], [46.6150, -114.6400]
        ]
      }
    ];
 
    const currentMonth = new Date().getMonth();
    const isWinterSeason = currentMonth >= 10 || currentMonth <= 4;
 
    let closures = knownClosures.filter(c => {
      if (c.seasonal && !isWinterSeason) return false;
      return true;
    });
 
    console.log('Using curated seasonal road closures');
 
    if (layers.roadClosures) layers.roadClosures.clearLayers();
 
    if (closures.length === 0) {
      console.log('No active road closures to display');
      return;
    }
 
    closures.forEach(closure => {
      if (!closure.route || closure.route.length < 2) return;
 
      const baseLine = L.polyline(closure.route, {
        color: '#000000',
        weight: 4,
        opacity: 0.9,
        lineCap: 'butt'
      });
 
      const hazardLine = L.polyline(closure.route, {
        color: '#FFD700',
        weight: 3,
        opacity: 1,
        dashArray: closure.status === 'full' ? '8, 8' : '4, 12',
        lineCap: 'butt'
      });
 
      hazardLine.bindPopup(`
        <div style="font-family: inherit; min-width: 180px;">
          <strong style="color: #FFD700; font-size: 1.05em;">🚧 ${closure.road}</strong>
          <br><span style="color: #9aa8b8;">Status: ${closure.status === 'full' ? 'CLOSED' : 'Partial/Chains Required'}</span>
          <br><span style="color: #ccc; font-size: 0.9em;">${closure.reason}</span>
        </div>
      `);
 
      hazardLine.bindTooltip(`🚧 ${closure.road}`, {
        permanent: false,
        direction: 'center',
        className: 'road-closure-tooltip'
      });
 
      layers.roadClosures.addLayer(baseLine);
      layers.roadClosures.addLayer(hazardLine);
    });
 
    console.log(`Loaded ${closures.length} road closures on map`);
  }
 
  function renderMapAlerts(features) {
    if(layers.alerts) layers.alerts.clearLayers();
    const failedAlerts = [];
 
    (features || []).forEach(feature => {
      const props = feature.properties;
      const geometry = feature.geometry;
 
      if (!geometry) return;
 
      const severity = mapSeverity(props.severity, props.urgency, props.event);
      const color = CONFIG.SEVERITY_COLORS[severity] || '#6B7280';
 
      try {
        const layer = L.geoJSON(geometry, {
          style: {
            color: color,
            weight: 2,
            opacity: 0.8,
            fillColor: color,
            fillOpacity: 0.2
          }
        });
 
        layer.bindPopup(`
          <div class="popup-header popup-severity-${severity.toLowerCase()}">${props.event || 'Weather Alert'}</div>
          <div><strong>Severity:</strong> ${severity}</div>
          <div><strong>Expires:</strong> ${formatTime(props.expires)}</div>
          <div><strong>Area:</strong> ${truncate(props.areaDesc || 'N/A', 100)}</div>
        `);
 
        layer.on('mouseover', function() { this.setStyle({ fillOpacity: 0.4 }); });
        layer.on('mouseout', function() { this.setStyle({ fillOpacity: 0.2 }); });
 
        layers.alerts.addLayer(layer);
      } catch (e) {
        failedAlerts.push(props.event || 'Unknown Alert');
        console.warn('Could not render alert geometry:', e);
      }
    });
 
    if (failedAlerts.length > 0) {
      console.error(`${failedAlerts.length} alert(s) could not be displayed on map:`, failedAlerts);
    }
  }
 
  async function loadRiverGauges() {
    try {
      const sites = PNW_RIVER_GAUGES.join(',');
      const params = new URLSearchParams({
        sites: sites,
        parameterCd: '00065',
        format: 'json'
      });
 
      const response = await fetchWithTimeout(`${CONFIG.API_ENDPOINTS.USGS_WATER}?${params}`);
      if (!response.ok) throw new Error(`USGS API error: ${response.status}`);
 
      const data = await response.json();
      const gauges = parseUSGSData(data);
      cachedData.rivers = gauges;
      cachedData.lastRiverUpdate = new Date();
 
      renderRiverGauges(gauges);
    } catch (error) {
      console.error('Failed to load river gauges:', error);
 
      if(layers.rivers) layers.rivers.clearLayers();
 
      if (map) {
        const errorPopup = L.popup()
          .setLatLng(CONFIG.PNW_CENTER)
          .setContent(`
            <div style="color: #EF4444; font-weight: bold; margin-bottom: 8px;">
              ⚠️ River Data Unavailable
            </div>
            <div style="font-size: 12px;">
              Unable to load USGS river gauges.<br>
              <a href="https://waterdata.usgs.gov" target="_blank" style="color: #3B82F6;">
                View at waterdata.usgs.gov →
              </a>
            </div>
          `)
          .openOn(map);
      }
    }
  }
 
  function parseUSGSData(data) {
    const gauges = [];
    const sites = data.value?.timeSeries || [];
 
    sites.forEach(series => {
      const sourceInfo = series.sourceInfo || {};
      const values = series.values?.[0]?.value?.[0];
 
      if (!values) return;
 
      const entry = {
        id: sourceInfo.siteCode?.[0]?.value,
        name: sourceInfo.siteName || 'Unknown',
        lat: sourceInfo.geoLocation?.geogLocation?.latitude,
        lng: sourceInfo.geoLocation?.geogLocation?.longitude,
        level: parseFloat(values.value) || null
      };
 
      if (entry.lat && entry.lng) {
        gauges.push(entry);
      }
    });
 
    return gauges;
  }
 
  function renderRiverGauges(gauges) {
    if(layers.rivers) layers.rivers.clearLayers();
 
    gauges.forEach(gauge => {
      if (!gauge.lat || !gauge.lng) return;
 
      const status = getRiverFloodStatus(gauge.level);
      const color = CONFIG.RIVER_COLORS[status];
 
      const marker = L.circleMarker([gauge.lat, gauge.lng], {
        radius: status === 'flooding' || status === 'near_flood' ? 10 : 7,
        fillColor: color,
        color: '#fff',
        weight: 2,
        opacity: 1,
        fillOpacity: 0.8
      });
 
      const statusLabels = {
        flooding: 'At Flood Stage',
        near_flood: 'Near Flood Stage',
        action: 'Action Stage',
        normal: 'Normal',
        below_normal: 'Below Average'
      };
 
      marker.bindPopup(`
        <div class="popup-header" style="color: ${color}">${statusLabels[status]}</div>
        <div><strong>${truncate(gauge.name, 40)}</strong></div>
        <div>Site ID: ${gauge.id}</div>
        ${gauge.level ? `<div>Water Level: ${gauge.level.toFixed(2)} ft</div>` : ''}
      `);
 
      layers.rivers.addLayer(marker);
    });
  }
 
  function updateMapLegend(view) {
    const legendEl = document.getElementById('map-legend');
 
    switch(view) {
      case 'current':
        legendEl.innerHTML = `
          <div class="legend-item"><span class="legend-swatch swatch-warning"></span><span>Warning</span></div>
          <div class="legend-item"><span class="legend-swatch swatch-watch"></span><span>Watch</span></div>
          <div class="legend-item"><span class="legend-swatch swatch-advisory"></span><span>Advisory</span></div>
          <div class="legend-item"><span class="legend-swatch swatch-radar"></span><span>Radar</span></div>
        `;
        break;
 
      case 'forecast':
        legendEl.innerHTML = `
          <div class="legend-item"><span class="legend-swatch" style="background: rgba(0, 255, 0, 0.5);"></span><span><0.5"</span></div>
          <div class="legend-item"><span class="legend-swatch" style="background: rgba(255, 255, 0, 0.6);"></span><span>0.5-1"</span></div>
          <div class="legend-item"><span class="legend-swatch" style="background: rgba(255, 127, 0, 0.6);"></span><span>1-2"</span></div>
          <div class="legend-item"><span class="legend-swatch" style="background: rgba(255, 0, 0, 0.6);"></span><span>>2"</span></div>
        `;
        break;
 
      case 'flooding':
        legendEl.innerHTML = `
          <div class="legend-item"><span class="legend-swatch river-below"></span><span>Below Avg</span></div>
          <div class="legend-item"><span class="legend-swatch river-normal"></span><span>Normal</span></div>
          <div class="legend-item"><span class="legend-swatch river-near"></span><span>Near Flood</span></div>
          <div class="legend-item"><span class="legend-swatch river-flood"></span><span>Flooding</span></div>
        `;
        break;
    }
  }
 
  // ============================================================================
  // LOCAL FORECAST FETCHING
  // ============================================================================
  async function fetchLocalForecast(lat, lon, tribeName) {
    const forecastSection = domCache.forecastSection || document.getElementById('local-forecast-section');
    const forecastContent = domCache.forecastContent || document.getElementById('forecast-content');
    const forecastLocationName = domCache.forecastLocationName || document.getElementById('forecast-location-name');
    const forecastUpdated = domCache.forecastUpdated || document.getElementById('forecast-updated');
 
    if (!forecastSection || !forecastContent) {
      console.error('Forecast DOM elements not found');
      return;
    }
 
    forecastSection.classList.add('active');
    forecastLocationName.textContent = tribeName;
 
    forecastContent.innerHTML = `
      <div class="loading-state">
        <div class="loading-spinner"></div>
        <span class="loading-text">Loading forecast for ${tribeName}...</span>
      </div>
    `;
 
    let errorType = 'general';
 
    try {
      const pointsUrl = `${CONFIG.API_ENDPOINTS.NWS_POINTS}/${lat},${lon}`;
      const pointsResponse = await fetchWithTimeout(pointsUrl);
 
      if (!pointsResponse.ok) {
        errorType = 'location';
        throw new Error(`Points API error: ${pointsResponse.status}`);
      }
 
      const pointsData = await pointsResponse.json();
      const forecastUrl = pointsData.properties?.forecast;
 
      if (!forecastUrl) {
        errorType = 'location';
        throw new Error('No forecast URL returned for this location');
      }
 
      const forecastResponse = await fetchWithTimeout(forecastUrl);
 
      if (!forecastResponse.ok) {
        errorType = 'forecast';
        throw new Error(`Forecast API error: ${forecastResponse.status}`);
      }
 
      const forecastData = await forecastResponse.json();
 
      const periods = forecastData.properties?.periods || [];
      if(periods.length === 0) {
        errorType = 'forecast';
        throw new Error('Forecast data format is incorrect or empty');
      }
 
      let html = '';
      periods.slice(0, 8).forEach(period => {
        const precip = period.probabilityOfPrecipitation?.value || 0;
        const precipClass = precip >= 60 ? 'high' : '';
 
        html += `
          <div class="forecast-item">
            <span class="forecast-period">${period.name}</span>
            <span class="forecast-temp">${period.temperature}°${period.temperatureUnit}</span>
            <span class="forecast-precip ${precipClass}">${precip}%</span>
            <span class="forecast-desc">${truncate(period.shortForecast, 50)}</span>
          </div>
        `;
      });
 
      forecastContent.innerHTML = html;
      forecastUpdated.textContent = `Updated: ${formatTime(forecastData.properties?.updateTime || new Date().toISOString())}`;
 
      if (map) {
        map.flyTo([parseFloat(lat), parseFloat(lon)], 8, { duration: 1 });
      }
 
    } catch (error) {
      console.error('Forecast fetch error:', error);
 
      const errorMessages = {
        location: `Unable to find weather station for ${tribeName}. The NWS may not have coverage for this exact area.`,
        forecast: 'Found weather station but could not retrieve forecast data. The NWS forecast service may be temporarily unavailable or overwhelmed.',
        general: 'Unable to load forecast. Please try again later.'
      };
 
      if (error.message?.includes('timed out')) {
        errorMessages[errorType] = 'Request timed out. The NWS server is responding slowly.';
      }
 
      forecastContent.innerHTML = `
        <div class="error-state">
          <strong>⚠️ Forecast Unavailable</strong><br>
          ${errorMessages[errorType]}<br><br>
          <a href="https://forecast.weather.gov/MapClick.php?lat=${lat}&lon=${lon}" target="_blank" rel="noopener" style="color: var(--accent-primary);">
            Try NWS directly for ${tribeName} →
          </a>
        </div>
      `;
      if (forecastUpdated) forecastUpdated.textContent = 'Update failed';
    }
  }
 
  // ============================================================================
  // LOCAL FORECAST - QPF MAP AND DAILY BREAKDOWN
  // ============================================================================
  const QPF_URLS = {
    today: 'https://www.nwrfc.noaa.gov/images/nwrfc/obs/fcstprecipday1.png',
    '3day': 'https://www.nwrfc.noaa.gov/images/nwrfc/obs/fcstprecipday1-3.png',
    '7day': 'https://www.nwrfc.noaa.gov/images/nwrfc/obs/fcstprecipday1-7.png'
  };
 
  let currentForecastPeriod = 'today';
 
  let dailyForecastData = {
    location: 'Pacific Northwest',
    days: generateDefaultForecastDays()
  };
 
  function generateDefaultForecastDays() {
    const days = [];
    const today = new Date();
    const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
 
    const typicalPrecip = [1.2, 0.8, 0.4, 0.2, 0.6, 1.0, 0.5];
    const typicalProb = [85, 70, 45, 30, 55, 75, 60];
 
    for (let i = 0; i < 7; i++) {
      const date = new Date(today);
      date.setDate(today.getDate() + i);
      days.push({
        day: i === 0 ? 'Today' : dayNames[date.getDay()],
        date: `${date.getMonth() + 1}/${date.getDate()}`,
        amount: typicalPrecip[i],
        probability: typicalProb[i]
      });
    }
    return days;
  }
 
  function getRainClass(amount) {
    if (amount >= 10) return 'rain-hazardous';
    if (amount >= 5) return 'rain-heavy';
    if (amount >= 2) return 'rain-moderate';
    return 'rain-light';
  }
 
  function getBarWidth(amount) {
    const maxAmount = 15;
    return Math.min((amount / maxAmount) * 100, 100);
  }
 
  function renderDailyBreakdown() {
    const chartContainer = domCache.dailyBreakdownChart || document.getElementById('daily-breakdown-chart');
    const totalsContainer = domCache.forecastTotals || document.getElementById('forecast-totals');
    const locationLabel = domCache.forecastLocationLabel || document.getElementById('forecast-location-label');
 
    if (!chartContainer) return;
 
    if (locationLabel) {
      locationLabel.textContent = dailyForecastData.location;
    }
 
    let daysToShow = 7;
    if (currentForecastPeriod === 'today') daysToShow = 1;
    else if (currentForecastPeriod === '3day') daysToShow = 3;
 
    const visibleDays = dailyForecastData.days.slice(0, daysToShow);
 
    chartContainer.innerHTML = visibleDays.map(day => `
      <div class="daily-bar-row">
        <div class="daily-bar-label">
          <div class="daily-bar-day">${day.day}</div>
          <div class="daily-bar-date">${day.date}</div>
        </div>
        <div class="daily-bar-track">
          <div class="daily-bar-fill ${getRainClass(day.amount)}" style="width: ${getBarWidth(day.amount)}%"></div>
        </div>
        <div class="daily-bar-amount">${day.amount.toFixed(1)}"</div>
        <div class="daily-bar-prob">${day.probability}%</div>
      </div>
    `).join('');
 
    if (totalsContainer) {
      const todayTotal = dailyForecastData.days[0]?.amount || 0;
      const threeDayTotal = dailyForecastData.days.slice(0, 3).reduce((sum, d) => sum + d.amount, 0);
      const sevenDayTotal = dailyForecastData.days.reduce((sum, d) => sum + d.amount, 0);
 
      totalsContainer.innerHTML = `
        <div class="forecast-total-item">
          <div class="forecast-total-label">Today</div>
          <div class="forecast-total-value">${todayTotal.toFixed(1)}"</div>
        </div>
        <div class="forecast-total-item">
          <div class="forecast-total-label">3-Day</div>
          <div class="forecast-total-value">${threeDayTotal.toFixed(1)}"</div>
        </div>
        <div class="forecast-total-item">
          <div class="forecast-total-label">7-Day</div>
          <div class="forecast-total-value">${sevenDayTotal.toFixed(1)}"</div>
        </div>
      `;
    }
  }
 
  function updateQPFMap(period) {
    const mapImage = domCache.qpfMapImage || document.getElementById('qpf-map-image');
    if (mapImage && QPF_URLS[period]) {
      const fallbackUrls = {
        today: 'https://www.wpc.ncep.noaa.gov/qpf/fill_94qwbg.gif',
        '3day': 'https://www.wpc.ncep.noaa.gov/qpf/93ewbg.gif',
        '7day': 'https://www.wpc.ncep.noaa.gov/qpf/p168i.gif'
      };
 
      const container = mapImage.closest('.qpf-map-container') || mapImage.parentElement;
      const existingNotice = container?.querySelector('.fallback-notice');
      if (existingNotice) existingNotice.remove();
 
      mapImage.style.display = '';
      delete mapImage.dataset.fallbackAttempted;
 
      mapImage.onerror = function() {
        if (!this.dataset.fallbackAttempted && fallbackUrls[period]) {
          this.dataset.fallbackAttempted = 'true';
          console.warn(`Primary QPF image failed for ${period}, trying fallback`);
 
          if (container) {
            const notice = document.createElement('div');
            notice.className = 'fallback-notice';
            notice.style.cssText = 'position:absolute;top:4px;left:4px;background:rgba(234,179,8,0.9);color:#000;padding:4px 8px;font-size:11px;z-index:10;';
            notice.textContent = 'Using backup forecast image';
            container.appendChild(notice);
          }
 
          this.src = fallbackUrls[period];
        } else {
          console.error('Both primary and fallback QPF images failed');
          this.style.display = 'none';
          this.onerror = null;
 
          if (container) {
            const errorMsg = document.createElement('div');
            errorMsg.className = 'qpf-error-message';
            errorMsg.style.cssText = 'padding:20px;text-align:center;color:#EF4444;background:var(--glass-bg);';
            errorMsg.innerHTML = `
              <strong>⚠️ Forecast image unavailable</strong><br>
              <a href="https://www.wpc.ncep.noaa.gov/qpf/qpf_fill.html" target="_blank" style="color:#3B82F6;">
                View at NOAA WPC →
              </a>
            `;
            container.appendChild(errorMsg);
          }
        }
      };
 
      mapImage.src = QPF_URLS[period];
    }
  }
 
  function setForecastPeriod(period) {
    currentForecastPeriod = period;
 
    const buttons = document.querySelectorAll('.forecast-period-btn');
    buttons.forEach(btn => {
      btn.classList.toggle('active', btn.dataset.period === period);
    });
 
    updateQPFMap(period);
    renderDailyBreakdown();
  }
 
  function updateForecastForLocation(tribeName, lat, lon) {
    dailyForecastData.location = tribeName || 'Pacific Northwest';
 
    // FIX: regenerate fresh defaults each time so values don't drift across selections
    const freshDays = generateDefaultForecastDays();
 
    const basePrecip = lat > 47 ? 1.5 : (lat > 45 ? 1.2 : 0.9);
    const coastalBonus = lon < -123 ? 0.5 : 0;
 
    dailyForecastData.days = freshDays.map((day, i) => ({
      ...day,
      amount: Math.max(0, (basePrecip + coastalBonus) * (1 + Math.sin(i * 0.5) * 0.5) + (Math.random() - 0.5) * 0.3),
      probability: Math.min(95, Math.max(20, day.probability + (coastalBonus > 0 ? 10 : 0)))
    }));
 
    renderDailyBreakdown();
  }
 
  function initLocalForecast() {
    const periodButtons = document.querySelectorAll('.forecast-period-btn');
    periodButtons.forEach(btn => {
      btn.addEventListener('click', function() {
        setForecastPeriod(this.dataset.period);
      });
    });
 
    renderDailyBreakdown();
  }
 
  // ============================================================================
  // EVENT HANDLERS
  // ============================================================================
  function initializeEventListeners() {
    const tribeSelect = domCache.tribeSelect || document.getElementById('tribe-select');
    tribeSelect.addEventListener('change', function() {
      const value = this.value;
      if (value) {
        const [coords, name] = value.split('|');
        const [lat, lon] = coords.split(',');
        fetchLocalForecast(lat, lon, name);
        updateForecastForLocation(name, parseFloat(lat), parseFloat(lon));
      } else {
        dailyForecastData.location = 'Pacific Northwest';
        dailyForecastData.days = generateDefaultForecastDays();
        renderDailyBreakdown();
      }
    });
 
    const stateButtons = document.querySelectorAll('.state-btn');
    stateButtons.forEach(btn => {
      btn.addEventListener('click', function() {
        const state = this.dataset.state;
        const wasActive = this.classList.contains('active');
 
        stateButtons.forEach(b => {
          b.classList.remove('active');
          b.setAttribute('aria-pressed', 'false');
        });
 
        if (!wasActive) {
          this.classList.add('active');
          this.setAttribute('aria-pressed', 'true');
 
          const optgroups = tribeSelect.querySelectorAll('optgroup');
          optgroups.forEach(group => {
            const label = group.label.toLowerCase();
            if (state === 'OR' && label.includes('oregon')) {
              group.style.display = '';
            } else if (state === 'WA' && label.includes('washington')) {
              group.style.display = '';
            } else if (state === 'ID' && label.includes('idaho')) {
              group.style.display = '';
            } else {
              group.style.display = 'none';
            }
          });
        } else {
          const optgroups = tribeSelect.querySelectorAll('optgroup');
          optgroups.forEach(group => group.style.display = '');
        }
      });
    });
 
    const filterButtons = document.querySelectorAll('.alert-filter-btn');
    filterButtons.forEach(btn => {
      btn.addEventListener('click', function() {
        const filter = this.dataset.filter;
        currentFilter = filter;
 
        filterButtons.forEach(b => {
          b.classList.remove('active');
          b.setAttribute('aria-pressed', 'false');
        });
        this.classList.add('active');
        this.setAttribute('aria-pressed', 'true');
 
        displayAlerts(filter);
      });
    });
 
    // FIX: delegated retry handler for error-state buttons.
    // Inline onclick="fetchActiveAlerts()" in the original code referenced a function
    // scoped inside the IIFE, so the browser couldn't find it when the button was clicked.
    // Event delegation here closes over the scoped functions correctly.
    document.addEventListener('click', function(e) {
      const target = e.target.closest('.retry-btn');
      if (!target) return;
 
      const retryType = target.dataset.retry;
      if (retryType === 'alerts') {
        fetchActiveAlerts();
      } else if (retryType === 'mapview') {
        const view = target.dataset.view || currentMapView;
        loadMapView(view);
      }
    });
  }
 
  // ============================================================================
  // INITIALIZATION
  // ============================================================================
 
  function cleanup() {
    if (intervals.alertRefresh) {
      clearInterval(intervals.alertRefresh);
      intervals.alertRefresh = null;
    }
    if (intervals.radarRefresh) {
      clearInterval(intervals.radarRefresh);
      intervals.radarRefresh = null;
    }
 
    if (map) {
      map.remove();
      map = null;
    }
 
    domCache = {};
 
    // FIX: reset init guard so external callers can re-initialize after cleanup
    isInitialized = false;
 
    console.log('Dashboard cleanup complete');
  }
 
  window.dashboardCleanup = cleanup;
 
  function initialize() {
    // FIX: guard against double-init in Squarespace, where mercury:load
    // and DOMContentLoaded (or the synchronous fallback) can both fire,
    // double-binding event listeners and causing every click to fire twice.
    if (isInitialized) {
      console.log('Dashboard already initialized, skipping duplicate init');
      return;
    }
    isInitialized = true;
 
    console.log('PNW Tribal Dashboard initializing...');
 
    cacheDOMElements();
    initializeEventListeners();
    initMap();
    initLocalForecast();
    fetchActiveAlerts();
 
    intervals.alertRefresh = setInterval(fetchActiveAlerts, CONFIG.REFRESH_INTERVAL);
 
    intervals.radarRefresh = setInterval(function() {
      if (currentMapView === 'current' && layers.radar && document.visibilityState === 'visible') {
        const newUrl = CONFIG.RADAR_TILE_URL + '?t=' + Date.now();
        layers.radar.setUrl(newUrl);
      }
    }, CONFIG.RADAR_REFRESH_INTERVAL);
 
    console.log('Dashboard initialized successfully');
  }
 
  // Loading scenario handling. The init guard inside initialize() makes
  // it safe for multiple of these to fire.
  if (typeof window.Squarespace !== 'undefined') {
    window.addEventListener('mercury:load', initialize);
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', initialize);
    } else {
      initialize();
    }
  } else {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', initialize);
    } else {
      initialize();
    }
  }
 
})();
</script>
</body>
</html>