Source: js/coalition-loader.js

/**
 * @module CoalitionIntelligence/StatusAnalysis
 * @category Political Analysis - Coalition Dynamics & Party Behavior
 * 
 * @description
 * **Coalition Status Intelligence & Party Dynamics Analyzer**
 * 
 * Real-time intelligence module for monitoring Swedish coalition formations,
 * party membership dynamics, leadership roles, and political alignment patterns.
 * Provides strategic assessment of the Tidö Agreement coalition (October 2022-)
 * and comprehensive party-level metrics across all 8 Riksdag parties.
 * 
 * ## Intelligence Focus
 * 
 * **Strategic Coalition Monitoring**:
 * - **Tidö Agreement**: M-SD-KD-L four-party coalition (2022-present)
 * - **Government Formation**: Minority coalition with external support
 * - **Stability Metrics**: Member cohesion, voting discipline, policy alignment
 * - **Alternative Scenarios**: Potential realignment patterns
 * 
 * ## Data Sources & Coverage
 * 
 * **CIA Platform Exports** (4 primary datasets):
 * 1. `view_riksdagen_party_summary_sample.csv` - Party statistics
 *    - Current member counts, committee assignments, leadership positions
 * 2. `view_riksdagen_party_role_member_sample.csv` - Leadership roles
 *    - Party leaders, parliamentary group leaders, committee chairs
 * 3. `view_riksdagen_politician_sample.csv` - MP profiles
 *    - Individual assignments, experience, voting records
 * 4. `view_riksdagen_politician_experience_summary_sample.csv` - Experience data
 *    - Parliamentary tenure, committee experience, leadership history
 * 
 * **Update Frequency**:
 * - Freshness Threshold: 7 days (weekly update cycle)
 * - Cache Strategy: localStorage with staleness detection
 * - Retry Logic: 3 attempts with 2-second backoff
 * 
 * ## Party Intelligence Profiles
 * 
 * **8 Swedish Political Parties**:
 * 
 * | Party | Code | Color    | Ideology         | Coalition Status |
 * |-------|------|----------|------------------|------------------|
 * | S     | S    | #E8112d  | Social Democrat  | Opposition       |
 * | M     | M    | #52BDEC  | Conservative     | Government       |
 * | SD    | SD   | #DDDD00  | Right Populist   | External Support |
 * | C     | C    | #009933  | Centre-Right     | Opposition       |
 * | V     | V    | #DA291C  | Left Socialist   | Opposition       |
 * | KD    | KD   | #000077  | Christian Dem    | Government       |
 * | L     | L    | #006AB3  | Liberal          | Government       |
 * | MP    | MP   | #83CF39  | Green            | Opposition       |
 * 
 * ## Coalition Analysis Metrics
 * 
 * **Key Performance Indicators**:
 * - **Membership Strength**: Active MPs per party (175 left + 174 right bloc)
 * - **Committee Influence**: Committee chair distribution analysis
 * - **Leadership Stability**: Party leader tenure tracking
 * - **Policy Cohesion**: Voting discipline within coalition
 * - **External Support**: SD cooperation patterns with government
 * 
 * ## Intelligence Methodologies
 * 
 * **Analytical Techniques**:
 * - **Coalition Mapping**: Network analysis of party relationships
 * - **Power Balance**: Seat distribution and influence metrics
 * - **Stability Assessment**: Historical coalition patterns (1971-2024)
 * - **Scenario Planning**: Alternative government formations
 * - **Predictive Modeling**: Coalition longevity forecasts
 * 
 * ## OSINT Data Pipeline
 * 
 * **Multi-Source Strategy**:
 * ```
 * Primary:   cia-data/party/view_riksdagen_party_summary_sample.csv (local)
 * Fallback:  GitHub Raw API (CIA repository master branch)
 * Cache:     localStorage with 7-day TTL
 * Validation: Schema checks, data completeness, freshness validation
 * ```
 * 
 * **Data Quality Assurance**:
 * - CSV format validation (UTF-8, comma-delimited)
 * - Required fields: party_id, party_short_name, member_count, role
 * - Range validation: member_count > 0, valid party codes
 * - Referential integrity: Cross-dataset party ID consistency
 * 
 * ## Visualization & Reporting
 * 
 * **Dashboard Components**:
 * 1. Coalition Status Card - Current government composition
 * 2. Party Strength Chart - Member counts and distribution
 * 3. Leadership Roster - Key political figures
 * 4. Committee Power Map - Committee chair distribution
 * 5. Historical Trends - Coalition stability over time
 * 
 * ## Multi-Language Support
 * 
 * **14 Languages**:
 * - Western: EN, SV, DA, NO, FI, DE, FR, ES, NL
 * - Middle Eastern: AR, HE (RTL support)
 * - East Asian: JA, KO, ZH
 * 
 * **Localized Content**:
 * - Party names (official vs. colloquial)
 * - Coalition terminology
 * - Political system concepts
 * 
 * ## GDPR Compliance
 * 
 * @gdpr Public political data only (Article 9(2)(e) - manifestly public)
 * All data sourced from official Riksdag records. No private information processed.
 * Party membership lists are public record per Swedish transparency laws.
 * 
 * ## Security Considerations
 * 
 * @security Low risk - Public data only, read-only operations
 * @risk Party affiliation data could be used for targeted political campaigns
 * 
 * **Mitigation**:
 * - Data already public in Riksdag database
 * - No aggregation beyond official statistics
 * - XSS protection via CSP headers
 * 
 * ## Performance Optimization
 * 
 * **Caching Strategy**:
 * - localStorage: 7-day cache reduces GitHub API calls
 * - Staleness detection: Auto-refresh on threshold breach
 * - Parallel loading: 4 CSV files fetched concurrently
 * - Error resilience: Graceful degradation with cached data
 * 
 * @intelligence Coalition dynamics analysis, party behavior monitoring
 * @osint Multi-source party data with fallback redundancy
 * @risk Political affiliation exposure, coalition strategy visibility
 * 
 * @author Hack23 AB - Coalition Intelligence Unit
 * @license Apache-2.0
 * @version 1.0.0
 * @since 2024
 * 
 * @see {@link https://github.com/Hack23/cia|CIA Platform Data Pipeline}
 * @see {@link party-dashboard.js|Party Performance Analytics}
 * @see {@link https://www.riksdagen.se|Official Riksdag Source}
 */

(function() {
  'use strict';

  // Configuration
  const CONFIG = {
    githubRawBase: 'https://raw.githubusercontent.com/Hack23/cia/master/service.data.impl/sample-data',
    dataSources: {
      partySummary: 'view_riksdagen_party_summary_sample.csv',
      partyRoles: 'view_riksdagen_party_role_member_sample.csv',
      politicianData: 'view_riksdagen_politician_sample.csv',
      experienceData: 'view_riksdagen_politician_experience_summary_sample.csv'
    },
    freshnessThreshold: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
    cachePrefix: 'coalition_data_',
    retryDelay: 2000,
    maxRetries: 3
  };

  // Party metadata with official names and colors
  const PARTY_INFO = {
    'S': { name: 'Social Democrats', nameShort: 'S', color: '#E8112d', fullName: 'Socialdemokraterna' },
    'M': { name: 'Moderates', nameShort: 'M', color: '#52BDEC', fullName: 'Moderaterna' },
    'SD': { name: 'Sweden Democrats', nameShort: 'SD', color: '#DDDD00', fullName: 'Sverigedemokraterna' },
    'C': { name: 'Centre Party', nameShort: 'C', color: '#009933', fullName: 'Centerpartiet' },
    'V': { name: 'Left Party', nameShort: 'V', color: '#DA291C', fullName: 'Vänsterpartiet' },
    'KD': { name: 'Christian Democrats', nameShort: 'KD', color: '#000077', fullName: 'Kristdemokraterna' },
    'L': { name: 'Liberals', nameShort: 'L', color: '#006AB3', fullName: 'Liberalerna' },
    'MP': { name: 'Green Party', nameShort: 'MP', color: '#83CF39', fullName: 'Miljöpartiet' }
  };

  // Multi-language translations
  const TRANSLATIONS = {
    en: {
      coalitionTitle: 'Current Coalition: Tidö Agreement',
      coalitionStatus: 'Formation: October 2022 | Status: Active',
      parliamentSeats: 'Parliament seats',
      governmentMembers: 'Government members',
      partyAssignments: 'Party assignments',
      leader: 'Leader',
      groupLeader: 'Group Leader',
      yearsInPolitics: 'Years in politics',
      totalDocuments: 'Documents authored',
      activityLevel: 'Activity level',
      specialization: 'Focus area',
      partyFocused: 'Party-focused',
      committeeFocused: 'Committee-focused',
      loadingMessage: 'Loading coalition data...',
      errorMessage: 'Unable to load coalition data',
      dataAttribution: 'Data from CIA Platform',
      lastUpdated: 'Last Updated'
    },
    sv: {
      coalitionTitle: 'Nuvarande koalition: Tidöavtalet',
      coalitionStatus: 'Bildande: oktober 2022 | Status: Aktiv',
      parliamentSeats: 'Riksdagsmandat',
      governmentMembers: 'Regeringsmedlemmar',
      partyAssignments: 'Partiuppdrag',
      leader: 'Partiledare',
      groupLeader: 'Gruppledare',
      yearsInPolitics: 'År i politiken',
      totalDocuments: 'Dokument författade',
      activityLevel: 'Aktivitetsnivå',
      specialization: 'Fokusområde',
      partyFocused: 'Partifokuserad',
      committeeFocused: 'Utskottsfokuserad',
      loadingMessage: 'Laddar koalitionsdata...',
      errorMessage: 'Kunde inte ladda koalitionsdata',
      dataAttribution: 'Data från CIA-plattformen',
      lastUpdated: 'Senast uppdaterad'
    },
    da: {
      coalitionTitle: 'Nuværende koalition: Tidö-aftalen',
      coalitionStatus: 'Dannelse: oktober 2022 | Status: Aktiv',
      parliamentSeats: 'Rigsdagsmandater',
      governmentMembers: 'Regeringsmedlemmer',
      partyAssignments: 'Partiopgaver',
      leader: 'Leder',
      groupLeader: 'Gruppeleder',
      yearsInPolitics: 'År i politik',
      totalDocuments: 'Dokumenter forfattet',
      activityLevel: 'Aktivitetsniveau',
      specialization: 'Fokusområde',
      partyFocused: 'Partifokuseret',
      committeeFocused: 'Udvalgsfokuseret',
      loadingMessage: 'Indlæser koalitionsdata...',
      errorMessage: 'Kunne ikke indlæse koalitionsdata',
      dataAttribution: 'Data fra CIA-platformen',
      lastUpdated: 'Senest opdateret'
    },
    no: {
      coalitionTitle: 'Nåværende koalisjon: Tidö-avtalen',
      coalitionStatus: 'Dannelse: oktober 2022 | Status: Aktiv',
      parliamentSeats: 'Riksdagsmandater',
      governmentMembers: 'Regjeringsmedlemmer',
      partyAssignments: 'Partioppgaver',
      leader: 'Leder',
      groupLeader: 'Gruppeleder',
      yearsInPolitics: 'År i politikken',
      totalDocuments: 'Dokumenter forfattet',
      activityLevel: 'Aktivitetsnivå',
      specialization: 'Fokusområde',
      partyFocused: 'Partifokusert',
      committeeFocused: 'Komitéfokusert',
      loadingMessage: 'Laster koalisjonsdata...',
      errorMessage: 'Kunne ikke laste koalisjonsdata',
      dataAttribution: 'Data fra CIA-plattformen',
      lastUpdated: 'Sist oppdatert'
    },
    de: {
      coalitionTitle: 'Aktuelle Koalition: Tidö-Vereinbarung',
      coalitionStatus: 'Bildung: Oktober 2022 | Status: Aktiv',
      parliamentSeats: 'Sitze im schwedischen Reichstag',
      governmentMembers: 'Regierungsmitglieder',
      partyAssignments: 'Parteiaufgaben',
      leader: 'Vorsitzender',
      groupLeader: 'Fraktionsvorsitzender',
      yearsInPolitics: 'Jahre in der Politik',
      totalDocuments: 'Verfasste Dokumente',
      activityLevel: 'Aktivitätsniveau',
      specialization: 'Schwerpunktbereich',
      partyFocused: 'Parteifokussiert',
      committeeFocused: 'Ausschussfokussiert',
      loadingMessage: 'Koalitionsdaten werden geladen...',
      errorMessage: 'Koalitionsdaten konnten nicht geladen werden',
      dataAttribution: 'Daten von der CIA-Plattform',
      lastUpdated: 'Zuletzt aktualisiert'
    },
    fr: {
      coalitionTitle: 'Coalition actuelle : Accord de Tidö',
      coalitionStatus: 'Formation : octobre 2022 | Statut : Actif',
      parliamentSeats: 'Sièges au Riksdag suédois',
      governmentMembers: 'Membres du gouvernement',
      partyAssignments: 'Affectations de parti',
      leader: 'Chef',
      groupLeader: 'Chef de groupe',
      yearsInPolitics: 'Années en politique',
      totalDocuments: 'Documents rédigés',
      activityLevel: 'Niveau d\'activité',
      specialization: 'Domaine d\'expertise',
      partyFocused: 'Axé parti',
      committeeFocused: 'Axé comité',
      loadingMessage: 'Chargement des données de coalition...',
      errorMessage: 'Impossible de charger les données de coalition',
      dataAttribution: 'Données de la plateforme CIA',
      lastUpdated: 'Dernière mise à jour'
    },
    es: {
      coalitionTitle: 'Coalición actual: Acuerdo de Tidö',
      coalitionStatus: 'Formación: octubre 2022 | Estado: Activo',
      parliamentSeats: 'Escaños del Riksdag sueco',
      governmentMembers: 'Miembros del gobierno',
      partyAssignments: 'Asignaciones de partido',
      leader: 'Líder',
      groupLeader: 'Líder del grupo',
      yearsInPolitics: 'Años en política',
      totalDocuments: 'Documentos escritos',
      activityLevel: 'Nivel de actividad',
      specialization: 'Área de enfoque',
      partyFocused: 'Enfocado en partido',
      committeeFocused: 'Enfocado en comité',
      loadingMessage: 'Cargando datos de coalición...',
      errorMessage: 'No se pudieron cargar los datos de coalición',
      dataAttribution: 'Datos de la plataforma CIA',
      lastUpdated: 'Última actualización'
    },
    fi: {
      coalitionTitle: 'Nykyinen koalitio: Tidö-sopimus',
      coalitionStatus: 'Muodostus: lokakuu 2022 | Tila: Aktiivinen',
      parliamentSeats: 'Riksdagin paikat',
      governmentMembers: 'Hallituksen jäseniä',
      partyAssignments: 'Puoluetehtävät',
      leader: 'Johtaja',
      groupLeader: 'Ryhmänjohtaja',
      yearsInPolitics: 'Vuotta politiikassa',
      totalDocuments: 'Kirjoitettuja asiakirjoja',
      activityLevel: 'Aktiivisuustaso',
      specialization: 'Painopistealue',
      partyFocused: 'Puoluepainotteinen',
      committeeFocused: 'Valiokuntapainotteinen',
      loadingMessage: 'Ladataan koalitiotietoja...',
      errorMessage: 'Koalitiotietoja ei voitu ladata',
      dataAttribution: 'Tiedot CIA-alustalta',
      lastUpdated: 'Viimeksi päivitetty'
    },
    nl: {
      coalitionTitle: 'Huidige coalitie: Tidö-akkoord',
      coalitionStatus: 'Vorming: oktober 2022 | Status: Actief',
      parliamentSeats: 'Zetels in het Zweedse Rijksdag',
      governmentMembers: 'Regeringsleden',
      partyAssignments: 'Partijfuncties',
      leader: 'Leider',
      groupLeader: 'Fractievoorzitter',
      yearsInPolitics: 'Jaren in de politiek',
      totalDocuments: 'Geschreven documenten',
      activityLevel: 'Activiteitsniveau',
      specialization: 'Focusgebied',
      partyFocused: 'Partijgericht',
      committeeFocused: 'Commissiegericht',
      loadingMessage: 'Coalitiegegevens laden...',
      errorMessage: 'Kan coalitiegegevens niet laden',
      dataAttribution: 'Gegevens van het CIA-platform',
      lastUpdated: 'Laatst bijgewerkt'
    },
    ar: {
      coalitionTitle: 'الائتلاف الحالي: اتفاقية تيدو',
      coalitionStatus: 'التشكيل: أكتوبر 2022 | الحالة: نشط',
      parliamentSeats: 'مقاعد البرلمان',
      governmentMembers: 'أعضاء الحكومة',
      partyAssignments: 'مهام الحزب',
      leader: 'القائد',
      groupLeader: 'قائد المجموعة',
      yearsInPolitics: 'سنوات في السياسة',
      totalDocuments: 'الوثائق المكتوبة',
      activityLevel: 'مستوى النشاط',
      specialization: 'مجال التركيز',
      partyFocused: 'التركيز على الحزب',
      committeeFocused: 'التركيز على اللجنة',
      loadingMessage: 'جاري تحميل بيانات الائتلاف...',
      errorMessage: 'تعذر تحميل بيانات الائتلاف',
      dataAttribution: 'البيانات من منصة CIA',
      lastUpdated: 'آخر تحديث'
    },
    he: {
      coalitionTitle: 'קואליציה נוכחית: הסכם טידו',
      coalitionStatus: 'הקמה: אוקטובר 2022 | סטטוס: פעיל',
      parliamentSeats: 'מושבי פרלמנט',
      governmentMembers: 'חברי ממשלה',
      partyAssignments: 'משימות מפלגה',
      leader: 'מנהיג',
      groupLeader: 'מנהיג הקבוצה',
      yearsInPolitics: 'שנים בפוליטיקה',
      totalDocuments: 'מסמכים שנכתבו',
      activityLevel: 'רמת פעילות',
      specialization: 'תחום התמחות',
      partyFocused: 'ממוקד מפלגה',
      committeeFocused: 'ממוקד וועדה',
      loadingMessage: 'טוען נתוני קואליציה...',
      errorMessage: 'לא ניתן לטעון נתוני קואליציה',
      dataAttribution: 'נתונים מפלטפורמת CIA',
      lastUpdated: 'עודכן לאחרונה'
    },
    ja: {
      coalitionTitle: '現在の連立:ティドー協定',
      coalitionStatus: '形成:2022年10月 | ステータス:アクティブ',
      parliamentSeats: '国会議席',
      governmentMembers: '政府メンバー',
      partyAssignments: '党の任務',
      leader: 'リーダー',
      groupLeader: 'グループリーダー',
      yearsInPolitics: '政治活動年数',
      totalDocuments: '作成文書',
      activityLevel: '活動レベル',
      specialization: '専門分野',
      partyFocused: '政党重視',
      committeeFocused: '委員会重視',
      loadingMessage: '連立データを読み込んでいます...',
      errorMessage: '連立データを読み込めませんでした',
      dataAttribution: 'CIAプラットフォームのデータ',
      lastUpdated: '最終更新'
    },
    ko: {
      coalitionTitle: '현재 연립: 티도 협정',
      coalitionStatus: '구성: 2022년 10월 | 상태: 활성',
      parliamentSeats: '의회 의석',
      governmentMembers: '정부 구성원',
      partyAssignments: '당 임무',
      leader: '리더',
      groupLeader: '그룹 리더',
      yearsInPolitics: '정치 경력',
      totalDocuments: '작성 문서',
      activityLevel: '활동 수준',
      specialization: '전문 분야',
      partyFocused: '정당 중심',
      committeeFocused: '위원회 중심',
      loadingMessage: '연립 데이터 로드 중...',
      errorMessage: '연립 데이터를 로드할 수 없습니다',
      dataAttribution: 'CIA 플랫폼의 데이터',
      lastUpdated: '마지막 업데이트'
    },
    zh: {
      coalitionTitle: '当前联盟:蒂德协议',
      coalitionStatus: '成立:2022年10月 | 状态:活跃',
      parliamentSeats: '议会席位',
      governmentMembers: '政府成员',
      partyAssignments: '党派任务',
      leader: '领导',
      groupLeader: '团队领导',
      yearsInPolitics: '从政年数',
      totalDocuments: '撰写文件',
      activityLevel: '活动水平',
      specialization: '专注领域',
      partyFocused: '政党导向',
      committeeFocused: '委员会导向',
      loadingMessage: '正在加载联盟数据...',
      errorMessage: '无法加载联盟数据',
      dataAttribution: '来自CIA平台的数据',
      lastUpdated: '最后更新'
    }
  };

  // Detect current language from HTML lang attribute
  function getCurrentLanguage() {
    const htmlLang = document.documentElement.lang || 'en';
    return htmlLang.substring(0, 2); // Get first 2 chars (en, sv, etc.)
  }

  // Get translations for current language with fallback to English
  function getTranslations() {
    const lang = getCurrentLanguage();
    return TRANSLATIONS[lang] || TRANSLATIONS.en;
  }

  /**
   * Parse CSV string into array of objects
   * @param {string} csvText - CSV content
   * @returns {Array<Object>} Parsed data
   */
  function parseCSV(csvText) {
    const lines = csvText.trim().split('\n');
    if (lines.length < 2) return [];

    const headers = lines[0].split(',').map(h => h.trim());
    const data = [];

    for (let i = 1; i < lines.length; i++) {
      const values = lines[i].split(',');
      if (values.length !== headers.length) continue;

      const row = {};
      headers.forEach((header, idx) => {
        row[header] = values[idx].trim();
      });
      data.push(row);
    }

    return data;
  }

  /**
   * Check if cached data is fresh
   * @param {string} key - Cache key
   * @returns {boolean} True if data is fresh
   */
  function isCacheFresh(key) {
    try {
      const cached = localStorage.getItem(CONFIG.cachePrefix + key);
      if (!cached) return false;

      const data = JSON.parse(cached);
      const age = Date.now() - data.timestamp;
      return age < CONFIG.freshnessThreshold;
    } catch (e) {
      console.error('Cache check error:', e);
      return false;
    }
  }

  /**
   * Get cached data if fresh
   * @param {string} key - Cache key
   * @returns {*} Cached data or null
   */
  function getCachedData(key) {
    try {
      if (!isCacheFresh(key)) return null;
      const cached = localStorage.getItem(CONFIG.cachePrefix + key);
      return cached ? JSON.parse(cached).data : null;
    } catch (e) {
      console.error('Cache retrieval error:', e);
      return null;
    }
  }

  /**
   * Cache data with timestamp
   * @param {string} key - Cache key
   * @param {*} data - Data to cache
   */
  function setCachedData(key, data) {
    try {
      const cacheObject = {
        data: data,
        timestamp: Date.now()
      };
      localStorage.setItem(CONFIG.cachePrefix + key, JSON.stringify(cacheObject));
    } catch (e) {
      console.error('Cache storage error:', e);
    }
  }

  /**
   * Fetch CSV data from GitHub with retry logic
   * @param {string} filename - CSV filename
   * @param {number} retryCount - Current retry attempt
   * @returns {Promise<string>} CSV content
   */
  async function fetchCSV(filename, retryCount = 0) {
    const url = `${CONFIG.githubRawBase}/${filename}`;
    
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      return await response.text();
    } catch (error) {
      console.error(`Fetch error for ${filename} (attempt ${retryCount + 1}):`, error);
      
      if (retryCount < CONFIG.maxRetries) {
        await new Promise(resolve => setTimeout(resolve, CONFIG.retryDelay));
        return fetchCSV(filename, retryCount + 1);
      }
      
      throw error;
    }
  }

  /**
   * Load party summary data (cached)
   * @returns {Promise<Array>} Party summary data
   */
  async function loadPartySummary() {
    const cacheKey = 'party_summary';
    const cached = getCachedData(cacheKey);
    if (cached) {
      console.log('Using cached party summary data');
      return cached;
    }

    console.log('Fetching party summary from GitHub...');
    const csvText = await fetchCSV(CONFIG.dataSources.partySummary);
    const data = parseCSV(csvText);
    
    // Filter for active parties only
    const activeParties = data.filter(row => row.active === 't');
    
    setCachedData(cacheKey, activeParties);
    return activeParties;
  }

  /**
   * Load party role/leader data (cached)
   * @returns {Promise<Array>} Party role data
   */
  async function loadPartyRoles() {
    const cacheKey = 'party_roles';
    const cached = getCachedData(cacheKey);
    if (cached) {
      console.log('Using cached party roles data');
      return cached;
    }

    console.log('Fetching party roles from GitHub...');
    const csvText = await fetchCSV(CONFIG.dataSources.partyRoles);
    const data = parseCSV(csvText);
    
    // Filter for active party leaders and group leaders
    const leaders = data.filter(row => 
      row.active === 't' && 
      (row.role_code === 'Partiledare' || row.role_code === 'Gruppledare')
    );
    
    setCachedData(cacheKey, leaders);
    return leaders;
  }

  /**
   * Load politician detailed data (cached)
   * @returns {Promise<Array>} Politician data
   */
  async function loadPoliticianData() {
    const cacheKey = 'politician_data';
    const cached = getCachedData(cacheKey);
    if (cached) {
      console.log('Using cached politician data');
      return cached;
    }

    console.log('Fetching politician data from GitHub...');
    const csvText = await fetchCSV(CONFIG.dataSources.politicianData);
    const data = parseCSV(csvText);
    
    setCachedData(cacheKey, data);
    return data;
  }

  /**
   * Load politician experience summary data (cached)
   * @returns {Promise<Array>} Experience data
   */
  async function loadExperienceData() {
    const cacheKey = 'experience_data';
    const cached = getCachedData(cacheKey);
    if (cached) {
      console.log('Using cached experience data');
      return cached;
    }

    console.log('Fetching experience data from GitHub...');
    const csvText = await fetchCSV(CONFIG.dataSources.experienceData);
    const data = parseCSV(csvText);
    
    setCachedData(cacheKey, data);
    return data;
  }

  /**
   * Get party leader name from role data
   * @param {Array} roleData - Party role data
   * @param {string} partyCode - Party code (e.g., 'M', 'SD')
   * @returns {Object} Leader info { name, roleType: 'leader'|'groupLeader' }
   */
  function getPartyLeader(roleData, partyCode) {
    // Prioritize Partiledare (Party Leader) over Gruppledare (Group Leader)
    const partyLeader = roleData.find(row => 
      row.party === partyCode && row.role_code === 'Partiledare'
    );
    
    if (partyLeader) {
      return {
        name: `${partyLeader.first_name} ${partyLeader.last_name}`,
        roleType: 'leader',
        personId: partyLeader.person_id
      };
    }

    const groupLeader = roleData.find(row => 
      row.party === partyCode && row.role_code === 'Gruppledare'
    );
    
    if (groupLeader) {
      return {
        name: `${groupLeader.first_name} ${groupLeader.last_name}`,
        roleType: 'groupLeader',
        personId: groupLeader.person_id
      };
    }

    return { name: 'Unknown', roleType: 'leader', personId: null };
  }

  /**
   * Get enhanced leader information
   * @param {Object} leader - Basic leader info
   * @param {Array} politicianData - Politician data
   * @param {Array} experienceData - Experience data  
   * @returns {Object} Enhanced leader info
   */
  function getEnhancedLeaderInfo(leader, politicianData, experienceData) {
    if (!leader.personId) return leader;

    // Find politician data
    const politician = politicianData.find(p => p.person_id === leader.personId);
    if (!politician) return leader;

    // Calculate years in politics
    const firstDate = new Date(politician.first_assignment_date);
    const yearsInPolitics = Math.floor((Date.now() - firstDate.getTime()) / (365.25 * 24 * 60 * 60 * 1000));

    // Get document activity
    const totalDocs = parseInt(politician.total_documents, 10) || 0;
    const activityLevel = politician.doc_activity_level || 'Unknown';

    // Determine specialization
    const partyDocs = parseInt(politician.party_motions, 10) || 0;
    const committeeDocs = parseInt(politician.committee_motions, 10) || 0;
    let specialization = 'Balanced';
    if (partyDocs > committeeDocs * 2) {
      specialization = 'Party-focused';
    } else if (committeeDocs > partyDocs * 2) {
      specialization = 'Committee-focused';
    }

    return {
      ...leader,
      yearsInPolitics,
      totalDocuments: totalDocs,
      activityLevel,
      specialization
    };
  }

  /**
   * Render coalition cards
   * @param {Array} partySummary - Party summary data
   * @param {Array} partyRoles - Party role data
   * @param {Array} politicianData - Politician data (optional)
   * @param {Array} experienceData - Experience data (optional)
   */
  function renderCoalition(partySummary, partyRoles, politicianData = [], experienceData = []) {
    const container = document.getElementById('coalition-status');
    if (!container) {
      console.error('Coalition status container not found');
      return;
    }

    const t = getTranslations();
    const cardsContainer = container.querySelector('.cards');
    if (!cardsContainer) {
      console.error('Cards container not found');
      return;
    }

    // Clear existing cards
    cardsContainer.innerHTML = '';

    // Filter to known parties only (have PARTY_INFO entry)
    const knownParties = partySummary.filter(party => PARTY_INFO[party.party]);

    // Sort parties by parliament seats (descending)
    const sortedParties = [...knownParties].sort((a, b) => {
      const seatsA = parseInt(a.total_active_parliament, 10) || 0;
      const seatsB = parseInt(b.total_active_parliament, 10) || 0;
      return seatsB - seatsA;
    });

    // Calculate total seats (only from known parties)
    const totalSeats = sortedParties.reduce((sum, party) => {
      return sum + (parseInt(party.total_active_parliament, 10) || 0);
    }, 0);

    // Render each party card
    sortedParties.forEach(party => {
      const partyCode = party.party;
      const partyInfo = PARTY_INFO[partyCode];
      if (!partyInfo) return; // Skip unknown parties (already filtered, but defensive)

      const parliamentSeats = parseInt(party.total_active_parliament, 10) || 0;
      const governmentMembers = parseInt(party.total_active_government, 10) || 0;
      const partyAssignments = parseInt(party.current_party_assignments, 10) || 0;
      
      const basicLeader = getPartyLeader(partyRoles, partyCode);
      const leader = getEnhancedLeaderInfo(basicLeader, politicianData, experienceData);
      const leaderLabel = t[leader.roleType] || t.leader; // Use roleType to select label

      // Create card using safe DOM APIs (XSS prevention)
      const card = document.createElement('div');
      card.className = 'card';

      // Scanner effect
      const scanner = document.createElement('div');
      scanner.className = 'scanner-effect';
      card.appendChild(scanner);

      // Party heading
      const heading = document.createElement('h3');
      heading.textContent = `${partyInfo.name} (${partyCode})`;
      card.appendChild(heading);

      // Party stats container
      const partyStats = document.createElement('div');
      partyStats.className = 'party-stats';

      // Parliament seats
      const seatsP = document.createElement('p');
      const seatsStrong = document.createElement('strong');
      seatsStrong.textContent = `${parliamentSeats} ${t.parliamentSeats}`;
      seatsP.appendChild(seatsStrong);
      partyStats.appendChild(seatsP);

      // Government members (only if > 0)
      if (governmentMembers > 0) {
        const govP = document.createElement('p');
        govP.textContent = `${governmentMembers} ${t.governmentMembers}`;
        partyStats.appendChild(govP);
      }

      // Party assignments
      const assignmentsP = document.createElement('p');
      assignmentsP.textContent = `${partyAssignments} ${t.partyAssignments}`;
      partyStats.appendChild(assignmentsP);

      card.appendChild(partyStats);

      // Party leader section
      const leaderSection = document.createElement('div');
      leaderSection.className = 'party-leader';
      
      const leaderName = document.createElement('p');
      const leaderStrong = document.createElement('strong');
      leaderStrong.textContent = `${leaderLabel}:`;
      leaderName.appendChild(leaderStrong);
      leaderName.appendChild(document.createTextNode(` ${leader.name}`));
      leaderSection.appendChild(leaderName);

      // Enhanced leader information (if available)
      if (leader.yearsInPolitics !== undefined) {
        const leaderDetails = document.createElement('div');
        leaderDetails.className = 'leader-details';
        leaderDetails.style.fontSize = '0.9em';
        leaderDetails.style.marginTop = '0.5rem';

        // Years in politics
        const yearsP = document.createElement('p');
        yearsP.textContent = `${t.yearsInPolitics}: ${leader.yearsInPolitics}`;
        yearsP.style.margin = '0.25rem 0';
        leaderDetails.appendChild(yearsP);

        // Documents authored
        if (leader.totalDocuments > 0) {
          const docsP = document.createElement('p');
          docsP.textContent = `${t.totalDocuments}: ${leader.totalDocuments}`;
          docsP.style.margin = '0.25rem 0';
          leaderDetails.appendChild(docsP);
        }

        // Activity level
        if (leader.activityLevel && leader.activityLevel !== 'Unknown') {
          const activityP = document.createElement('p');
          activityP.textContent = `${t.activityLevel}: ${leader.activityLevel}`;
          activityP.style.margin = '0.25rem 0';
          leaderDetails.appendChild(activityP);
        }

        // Specialization
        if (leader.specialization && leader.specialization !== 'Balanced') {
          const specP = document.createElement('p');
          const specKey = leader.specialization === 'Party-focused' ? 'partyFocused' : 'committeeFocused';
          specP.textContent = `${t.specialization}: ${t[specKey]}`;
          specP.style.margin = '0.25rem 0';
          leaderDetails.appendChild(specP);
        }

        leaderSection.appendChild(leaderDetails);
      }

      card.appendChild(leaderSection);

      cardsContainer.appendChild(card);
    });

    // Update coalition status text
    const statusP = container.querySelector('p');
    if (statusP) {
      statusP.textContent = `${t.coalitionStatus} | Total Seats: ${totalSeats} of 349`;
    }

    console.log(`Rendered ${sortedParties.length} active parties with ${totalSeats} total seats`);
  }

  /**
   * Show loading state
   */
  function showLoading() {
    const container = document.getElementById('coalition-status');
    if (!container) return;

    const cardsContainer = container.querySelector('.cards');
    if (cardsContainer) {
      const t = getTranslations();
      cardsContainer.innerHTML = `<p class="loading-message">${t.loadingMessage}</p>`;
    }
  }

  /**
   * Show error state
   * @param {Error} error - Error object
   */
  function showError(error) {
    const container = document.getElementById('coalition-status');
    if (!container) return;

    const cardsContainer = container.querySelector('.cards');
    if (cardsContainer) {
      const t = getTranslations();
      const errorP = document.createElement('p');
      errorP.className = 'error-message';
      errorP.textContent = `${t.errorMessage}: ${error.message}`;
      cardsContainer.innerHTML = '';
      cardsContainer.appendChild(errorP);
    }
    console.error('Coalition loader error:', error);
  }

  /**
   * Initialize coalition loader
   */
  async function init() {
    try {
      showLoading();

      // Load data from CSV files (politician and experience data are optional for backward compatibility)
      const [partySummary, partyRoles, politicianData, experienceData] = await Promise.all([
        loadPartySummary(),
        loadPartyRoles(),
        loadPoliticianData().catch(err => {
          console.warn('Could not load politician data:', err);
          return [];
        }),
        loadExperienceData().catch(err => {
          console.warn('Could not load experience data:', err);
          return [];
        })
      ]);

      console.log('Loaded data:', {
        parties: partySummary.length,
        leaders: partyRoles.length,
        politicians: politicianData.length,
        experiences: experienceData.length
      });

      // Render coalition cards
      renderCoalition(partySummary, partyRoles, politicianData, experienceData);

    } catch (error) {
      showError(error);
    }
  }

  // Auto-initialize when DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

  // Expose for manual refresh if needed
  window.CoalitionLoader = {
    refresh: init,
    clearCache: function() {
      Object.keys(localStorage).forEach(key => {
        if (key.startsWith(CONFIG.cachePrefix)) {
          localStorage.removeItem(key);
        }
      });
      console.log('Coalition cache cleared');
    }
  };

})();