<%- include('../partials/head', { title, bodyClass: `app-page app-screen-page analysis-app-page ${typeof embeddedAnalysis !== 'undefined' && embeddedAnalysis ? 'analysis-embed-page' : ''}` }) %>
<%
  const pageEmbeddedAnalysis = typeof embeddedAnalysis !== 'undefined' && embeddedAnalysis;
%>
<% if (!pageEmbeddedAnalysis) { %>
  <%- include('../partials/app-header') %>
<% } %>

<%
  const pageAnalysisLoading = typeof isAnalysisLoading !== 'undefined' && isAnalysisLoading;
  const pageAnalysisLocked = typeof analysisLocked !== 'undefined' && analysisLocked;
  const safeMatch = match || {};
  const displayAnalysis = analysis || {
    title: 'Cargando información...',
    summary: 'TopStats récupère les informations utiles du match avant d’afficher une analyse propre.',
    team_form: 'Cargando la forma reciente de los equipos.',
    key_stats: 'Cargando señales estadísticas y mercados disponibles.',
    strengths: 'Cargando puntos fuertes antes del partido.',
    risks: 'Cargando riesgos a vigilar.'
  };
  const pageAuthLocked = typeof authRequiredForAdvice !== 'undefined' && authRequiredForAdvice;
  const lockedAdviceCopy = 'Contenu réservé aux membres connectés';
  const lockedAdviceHref = pageAuthLocked ? '/connexion' : '/pro';
  const lockedAdviceAction = pageAuthLocked ? 'Entrar' : 'Desbloquear';
  const pageLocked = typeof locked !== 'undefined' && locked;
  const recommendationItems = typeof recommendations !== 'undefined' && Array.isArray(recommendations) ? recommendations : [];
  const recommendationDisplayKey = (recommendation) => [
    String(recommendation && (recommendation.title || '')).trim().toLowerCase(),
    String(recommendation && (recommendation.market || recommendation.recommendation_type || '')).trim().toLowerCase(),
    String(recommendation && (recommendation.market_value || '')).trim().toLowerCase(),
    String(recommendation && (recommendation.odds || '')).trim()
  ].filter(Boolean).join('|') || String(recommendation && (recommendation.id || recommendation.recommendation_key || '')).trim().toLowerCase();
  const allRecommendations = pageAnalysisLoading ? [] : recommendationItems.filter((recommendation, index, list) => {
    const key = recommendationDisplayKey(recommendation);
    return key && list.findIndex((item) => recommendationDisplayKey(item) === key) === index;
  });
  const mainRecommendation = allRecommendations.length ? allRecommendations[0] : null;
  const strongestRecommendation = !pageAnalysisLoading && typeof topConfidenceRecommendation !== 'undefined' && topConfidenceRecommendation ? topConfidenceRecommendation : null;
  const strongestRecommendationOdd = strongestRecommendation && Number.isFinite(Number(strongestRecommendation.odds)) ? Number(strongestRecommendation.odds) : null;
  const matchOdds = !pageAnalysisLoading && typeof matchOdds1x2 !== 'undefined' && matchOdds1x2 ? matchOdds1x2 : null;
  const safeGeneralStatsOdds = !pageAnalysisLoading && typeof generalStatsOdds !== 'undefined' && generalStatsOdds ? generalStatsOdds : {};
  const safePreMatchSummary = typeof preMatchSummary !== 'undefined' ? preMatchSummary : null;
  const quality = pageAnalysisLoading ? null : (credibility || (mainRecommendation && mainRecommendation.data_quality) || (safePreMatchSummary && safePreMatchSummary.credibility) || null);
  const qualitySources = Array.isArray(quality && quality.sources) ? quality.sources : [];
  const availableSources = qualitySources.filter((source) => source.available);
  const computedQualityScore = quality && quality.score !== undefined
    ? Number(quality.score)
    : Math.round((availableSources.length / Math.max(qualitySources.length || 1, 1)) * 100);
  const qualityScore = Math.max(0, Math.min(100, Number.isFinite(computedQualityScore) ? computedQualityScore : 0));
  const hiddenCount = typeof hiddenRecommendationsCount !== 'undefined' ? hiddenRecommendationsCount : 0;
  const freeLimit = Number(freeMaxOdds || 1.45);
  const strongestRecommendationLocked = Boolean((pageAuthLocked && strongestRecommendation) || (pageLocked && strongestRecommendationOdd && strongestRecommendationOdd > freeLimit));
  const hasScore = safeMatch.score_home !== null && safeMatch.score_home !== undefined && safeMatch.score_away !== null && safeMatch.score_away !== undefined;
  const hasOnlyProRecommendations = !pageAuthLocked && !pageAnalysisLoading && pageLocked && hiddenCount > 0 && !allRecommendations.length;
  const scoreScenarioData = !pageAnalysisLoading && typeof scoreScenarios !== 'undefined' && scoreScenarios ? scoreScenarios : null;
  const scoreScenarioItems = scoreScenarioData && Array.isArray(scoreScenarioData.items) ? scoreScenarioData.items : [];
  const scorerItems = !pageAnalysisLoading && typeof scorerWatchlist !== 'undefined' && Array.isArray(scorerWatchlist) ? scorerWatchlist : [];
  const scorerAdviceItems = !pageAnalysisLoading && typeof scorerRecommendations !== 'undefined' && Array.isArray(scorerRecommendations) ? scorerRecommendations : [];
  const hiddenScorerCount = typeof hiddenScorerRecommendationsCount !== 'undefined' ? hiddenScorerRecommendationsCount : 0;
  const hasOnlyProScorerRecommendations = !pageAuthLocked && !pageAnalysisLoading && hiddenScorerCount > 0 && !scorerAdviceItems.length;
  const analysisUrl = typeof analysisDataUrl !== 'undefined' ? analysisDataUrl : '';
  const editorialFallback = [
    displayAnalysis.summary,
    displayAnalysis.explanation,
    displayAnalysis.context,
    displayAnalysis.weaknesses || displayAnalysis.risks
  ].filter(Boolean).join('\n\n');
  const professionalAnalysisParagraphs = String(editorialFallback || '')
    .split(/\n{2,}/)
    .map((item) => item.replace(/\s+/g, ' ').trim())
    .filter(Boolean)
    .filter((item, index, list) => item && list.indexOf(item) === index)
    .slice(0, 4);
  const matchBackHref = safeMatch && safeMatch.kickoff_at
    ? `/matchs?date=${String(safeMatch.kickoff_at).slice(0, 10)}`
    : '/matchs';
  const kickoffDate = safeMatch.kickoff_at ? new Date(safeMatch.kickoff_at) : null;
  const compactMatchDate = kickoffDate && !Number.isNaN(kickoffDate.getTime())
    ? kickoffDate.toLocaleDateString('es-ES', { day: 'numeric', month: 'short' }).replace(/\.$/, '') + '.'
    : '';
  const safeNumber = (value, fallback = 0) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : fallback;
  };
  const formatMetric = (value, suffix = '') => {
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) return '-';
    const rounded = Math.abs(parsed) >= 10 ? Math.round(parsed) : Math.round(parsed * 10) / 10;
    return `${String(rounded).replace('.', ',')}${suffix}`;
  };
  const recentHome = safePreMatchSummary && safePreMatchSummary.recentForm ? safePreMatchSummary.recentForm.home : null;
  const recentAway = safePreMatchSummary && safePreMatchSummary.recentForm ? safePreMatchSummary.recentForm.away : null;
  const recentCount = (form) => Math.max(1, safeNumber(form && form.matchCount, 5));
  const formWins = (form) => safeNumber(form && form.wins, 0);
  const formDraws = (form) => safeNumber(form && form.draws, 0);
  const formLosses = (form) => safeNumber(form && form.losses, 0);
  const avgFor = (form) => safeNumber(form && form.avgGoalsFor, 0);
  const avgAgainst = (form) => safeNumber(form && form.avgGoalsAgainst, 0);
  const pointsPerMatch = (form) => ((formWins(form) * 3) + formDraws(form)) / recentCount(form);
  const winRate = (form) => (formWins(form) / recentCount(form)) * 100;
  const drawRate = (form) => (formDraws(form) / recentCount(form)) * 100;
  const lossRate = (form) => (formLosses(form) / recentCount(form)) * 100;
  const statMetricRows = [
    { label: 'Buts marqués', home: avgFor(recentHome), away: avgFor(recentAway), suffix: '' },
    { label: 'Buts encaissés', home: avgAgainst(recentHome), away: avgAgainst(recentAway), suffix: '' },
    { label: 'Différence de buts', home: avgFor(recentHome) - avgAgainst(recentHome), away: avgFor(recentAway) - avgAgainst(recentAway), suffix: '' },
    { label: 'Buts impliqués', home: avgFor(recentHome) + avgAgainst(recentHome), away: avgFor(recentAway) + avgAgainst(recentAway), suffix: '' },
    { label: 'Points par match', home: pointsPerMatch(recentHome), away: pointsPerMatch(recentAway), suffix: '' },
    { label: 'Victoires (%)', home: winRate(recentHome), away: winRate(recentAway), suffix: '%' },
    { label: 'Nuls (%)', home: drawRate(recentHome), away: drawRate(recentAway), suffix: '%' },
    { label: 'Défaites (%)', home: lossRate(recentHome), away: lossRate(recentAway), suffix: '%' }
  ].map((row) => {
    const max = Math.max(Math.abs(row.home), Math.abs(row.away), 1);
    return {
      ...row,
      homePct: Math.max(3, Math.min(100, Math.round((Math.abs(row.home) / max) * 100))),
      awayPct: Math.max(3, Math.min(100, Math.round((Math.abs(row.away) / max) * 100)))
    };
  });
  const hasRecentStats = Boolean((recentHome && recentHome.available) || (recentAway && recentAway.available));
  const lineupItems = typeof lineups !== 'undefined' && Array.isArray(lineups) ? lineups : [];
  const normalizeName = (value) => String(value || '').trim().toLowerCase();
  const lineupForSide = (side) => {
    const wantedId = side === 'home' ? safeMatch.home_team_id : safeMatch.away_team_id;
    const wantedName = side === 'home' ? safeMatch.home_team : safeMatch.away_team;
    return lineupItems.find((lineup) => (
      lineup && lineup.team && (
        (wantedId && String(lineup.team.id || '') === String(wantedId))
        || normalizeName(lineup.team.name) === normalizeName(wantedName)
      )
    )) || null;
  };
  const homeLineup = lineupForSide('home');
  const awayLineup = lineupForSide('away');
  const lineupHasPlayers = (lineup) => Boolean(lineup && Array.isArray(lineup.start_xi) && lineup.start_xi.length);
  const hasLineupDisplay = lineupHasPlayers(homeLineup) || lineupHasPlayers(awayLineup);
  const lineupStatusCopy = hasLineupDisplay
    ? (lineupItems.some((lineup) => lineup && lineup.status === 'official') ? 'Composition officielle publiée' : 'Composition probable estimée par TopStats')
    : 'Compositions non publiées';
  const playerShortName = (name) => {
    const parts = String(name || '').trim().split(/\s+/).filter(Boolean);
    if (!parts.length) return 'Joueur';
    if (parts.length === 1) return parts[0].slice(0, 12);
    const last = parts[parts.length - 1];
    return last.length >= 4 ? last.slice(0, 12) : parts.slice(0, 2).join(' ').slice(0, 12);
  };
  const playerInitials = (name) => String(name || 'J')
    .split(/\s+/)
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0])
    .join('')
    .toUpperCase();
  const sortedLineupPlayers = (lineup) => (lineup && Array.isArray(lineup.start_xi) ? lineup.start_xi : [])
    .slice()
    .sort((a, b) => String(a.grid || '').localeCompare(String(b.grid || ''), 'es', { numeric: true }));
  const lineupMiniPositionStyle = (player, index, lineup) => {
    const players = sortedLineupPlayers(lineup);
    const playerRow = (item, fallbackIndex = 0) => {
      const parsed = Number(String(item?.grid || '').split(':')[0]);
      return Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, 5) : Math.min(5, Math.floor(fallbackIndex / 3) + 1);
    };
    const playerCol = (item, fallbackIndex = 0) => {
      const parsed = Number(String(item?.grid || '').split(':')[1]);
      return Number.isFinite(parsed) && parsed > 0 ? parsed : ((fallbackIndex % 3) + 1);
    };
    const grid = String(player.grid || '');
    const [rawRow, rawCol] = grid.split(':').map((item) => Number(item));
    const row = Number.isFinite(rawRow) && rawRow > 0 ? Math.min(rawRow, 5) : playerRow(player, index);
    const sameRow = players
      .map((item, itemIndex) => ({ item, itemIndex, row: playerRow(item, itemIndex), col: playerCol(item, itemIndex) }))
      .filter((item) => item.row === row);
    const colCount = Math.max(1, ...sameRow.map((item) => item.col), sameRow.length);
    const col = Number.isFinite(rawCol) && rawCol > 0 ? Math.min(rawCol, colCount) : playerCol(player, index);
    const rowCount = Math.max(4, ...players.map((item, itemIndex) => playerRow(item, itemIndex)), row);
    const x = colCount <= 1 ? 50 : 14 + ((col - 1) / Math.max(1, colCount - 1)) * 72;
    const y = rowCount <= 1 ? 50 : 84 - ((row - 1) / Math.max(1, rowCount - 1)) * 70;
    return `--x:${Math.round(x * 10) / 10}%;--y:${Math.round(y * 10) / 10}%;`;
  };
  const safeVoteStats = typeof voteStats !== 'undefined' && voteStats ? voteStats : { total: 0, selected: null, options: {} };
  const voteOption = (choice) => (safeVoteStats.options && safeVoteStats.options[choice]) || { count: 0, percent: 0 };
  const voteLabel = (count) => `${Number(count || 0)} vote${Number(count || 0) > 1 ? 's' : ''}`;
  const numberFr = (value, fallback = '-') => {
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) return fallback;
    const rounded = Math.abs(parsed) >= 10 ? Math.round(parsed) : Math.round(parsed * 10) / 10;
    return String(rounded).replace('.', ',');
  };
  const percentInt = (value) => Math.max(0, Math.min(100, Math.round(Number(value || 0))));
  const metricPair = (label, home, away, options = {}) => {
    const homeValue = Number(home);
    const awayValue = Number(away);
    const max = Math.max(Math.abs(homeValue || 0), Math.abs(awayValue || 0), 1);
    return {
      label,
      home: Number.isFinite(homeValue) ? homeValue : null,
      away: Number.isFinite(awayValue) ? awayValue : null,
      homePct: Number.isFinite(homeValue) ? Math.max(5, Math.round((Math.abs(homeValue) / max) * 50)) : 0,
      awayPct: Number.isFinite(awayValue) ? Math.max(5, Math.round((Math.abs(awayValue) / max) * 50)) : 0,
      suffix: options.suffix || ''
    };
  };
  const rawLiveStatSummary = typeof liveStatSummary !== 'undefined' ? liveStatSummary : null;
  const statusText = String(safeMatch.status_short || safeMatch.status || '').toLowerCase();
  const isPastScoredMatch = Boolean(hasScore && kickoffDate && !Number.isNaN(kickoffDate.getTime()) && kickoffDate.getTime() < Date.now() - (2 * 60 * 60 * 1000));
  const isFinishedMatchPage = Boolean(
    safeMatch.is_finished
    || safeMatch.isFinished
    || isPastScoredMatch
    || statusText.includes('termin')
    || ['ft', 'aet', 'pen', 'finished'].includes(statusText)
  );
  const isLiveMatchPage = Boolean(
    safeMatch.is_live
    || safeMatch.isLive
    || statusText.includes('live')
    || statusText.includes('direct')
    || statusText.includes('mi-temps')
    || ['1h', '2h', 'ht', 'et', 'bt', 'p'].includes(statusText)
  );
  const shouldUseRealStats = isLiveMatchPage || isFinishedMatchPage;
  const parseMetricNumber = (value) => {
    if (value === null || value === undefined || value === '—' || value === '-') return null;
    const parsed = Number(String(value).replace('%', '').replace(',', '.').trim());
    return Number.isFinite(parsed) ? parsed : null;
  };
  const statDisplayValue = (row, side) => {
    const value = numberFr(row[side]);
    if (value === '-') return value;
    return row.suffix === '%' ? `${value}%` : value;
  };
  const liveLabel = (label) => ({
    'Tirs': 'Tirs totaux',
    'Buts attendus': 'Expected Goals (xG)',
    'Possession': 'Possession de balle (%)',
    'Passes réussies': 'Passes réussies',
    'Précision passes': 'Précision passes (%)'
  }[label] || label);
  const liveSuffix = (label, home, away) => (
    String(label || '').includes('Possession')
    || String(label || '').includes('Précision')
    || String(home || '').includes('%')
    || String(away || '').includes('%')
  ) ? '%' : '';
  const estimatedHomeXg = scoreScenarioData && scoreScenarioData.home_expected_goals !== undefined ? Number(scoreScenarioData.home_expected_goals) : (avgFor(recentHome) ? (avgFor(recentHome) * 0.86) : null);
  const estimatedAwayXg = scoreScenarioData && scoreScenarioData.away_expected_goals !== undefined ? Number(scoreScenarioData.away_expected_goals) : (avgFor(recentAway) ? (avgFor(recentAway) * 0.86) : null);
  const estimatedShots = (form, multiplier = 3.8) => {
    if (!form || !form.available) return null;
    return Math.max(3.2, (avgFor(form) * multiplier) + (avgAgainst(form) * .8));
  };
  const zoneStatRows = [
    metricPair('Buts marqués', avgFor(recentHome), avgFor(recentAway)),
    metricPair('Expected Goals (xG)', estimatedHomeXg, estimatedAwayXg),
    metricPair('Buts encaissés', avgAgainst(recentHome), avgAgainst(recentAway)),
    metricPair('Tirs totaux', estimatedShots(recentHome), estimatedShots(recentAway)),
    metricPair('Tirs cadrés', avgFor(recentHome) ? avgFor(recentHome) * 1.55 : null, avgFor(recentAway) ? avgFor(recentAway) * 1.55 : null),
    metricPair('Tirs non cadrés', estimatedShots(recentHome, 2.1), estimatedShots(recentAway, 2.1)),
    metricPair('Possession de balle (%)', recentHome && recentAway ? 48 + ((pointsPerMatch(recentHome) - pointsPerMatch(recentAway)) * 6) : null, recentHome && recentAway ? 52 + ((pointsPerMatch(recentAway) - pointsPerMatch(recentHome)) * 6) : null, { suffix: '%' }),
    metricPair('Corners', avgFor(recentHome) ? avgFor(recentHome) * 2.1 : null, avgFor(recentAway) ? avgFor(recentAway) * 2.1 : null)
  ];
  const liveStatRows = rawLiveStatSummary && Array.isArray(rawLiveStatSummary.rows)
    ? rawLiveStatSummary.rows
      .map((row) => metricPair(
        liveLabel(row.label),
        parseMetricNumber(row.home),
        parseMetricNumber(row.away),
        { suffix: liveSuffix(row.label, row.home, row.away) }
      ))
      .filter((row) => row.home !== null || row.away !== null)
    : [];
  const liveZeroRows = [
    metricPair('Tirs cadrés', 0, 0),
    metricPair('Tirs totaux', 0, 0),
    metricPair('Expected Goals (xG)', 0, 0),
    metricPair('Possession de balle (%)', 0, 0, { suffix: '%' }),
    metricPair('Corners', 0, 0),
    metricPair('Tirs dans la surface', 0, 0),
    metricPair('Passes réussies', 0, 0),
    metricPair('Précision passes (%)', 0, 0, { suffix: '%' })
  ];
  const displayedStatRows = shouldUseRealStats
    ? (liveStatRows.length ? liveStatRows : (isLiveMatchPage ? liveZeroRows : []))
    : zoneStatRows;
  const displayedStatsSubtitle = shouldUseRealStats
    ? (displayedStatRows.length ? (isFinishedMatchPage ? 'Statistiques réelles finales du match' : 'Statistiques réelles du match') : 'Statistiques réelles indisponibles')
    : 'Moyennes par match sur les 5 derniers matchs';
  const realStatsEmptyCopy = isFinishedMatchPage
    ? 'Les statistiques finales ne sont pas encore disponibles dans le flux sportif.'
    : 'Les statistiques réelles du match ne sont pas encore disponibles.';
  const recentFixtureSource = typeof recentFormFixtures !== 'undefined' && recentFormFixtures ? recentFormFixtures : { home: [], away: [] };
  const h2hSource = typeof h2hFixtures !== 'undefined' && Array.isArray(h2hFixtures) ? h2hFixtures : [];
  const standingGroups = typeof standings !== 'undefined' && Array.isArray(standings) ? standings : [];
  const fixtureSide = (fixture, side) => {
    const wantedId = side === 'home' ? safeMatch.home_team_id : safeMatch.away_team_id;
    const wantedName = normalizeName(side === 'home' ? safeMatch.home_team : safeMatch.away_team);
    if (wantedId && String(fixture?.teams?.home?.id || '') === String(wantedId)) return 'home';
    if (wantedId && String(fixture?.teams?.away?.id || '') === String(wantedId)) return 'away';
    if (wantedName && normalizeName(fixture?.teams?.home?.name).includes(wantedName)) return 'home';
    if (wantedName && normalizeName(fixture?.teams?.away?.name).includes(wantedName)) return 'away';
    return side;
  };
  const recentRowsForSide = (side) => (Array.isArray(recentFixtureSource[side]) ? recentFixtureSource[side] : []).slice(0, 5);
  const fixtureScoreNumber = (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : null;
  };
  const eventBelongsToMatchSide = (event, side) => {
    const wantedId = side === 'home' ? safeMatch.home_team_id : safeMatch.away_team_id;
    const wantedName = normalizeName(side === 'home' ? safeMatch.home_team : safeMatch.away_team);
    const wantedApiName = normalizeName(side === 'home' ? safeMatch.home_team_api : safeMatch.away_team_api);
    const teamId = event?.team?.id;
    const teamName = normalizeName(event?.team?.name);
    if (wantedId && String(teamId || '') === String(wantedId)) return true;
    return Boolean(teamName && (teamName === wantedName || teamName === wantedApiName || wantedName.includes(teamName) || teamName.includes(wantedName)));
  };
  const firstGoalSideForFixture = (fixture, side) => {
    const events = Array.isArray(fixture?.goal_events) ? fixture.goal_events : [];
    const firstGoal = events
      .filter((event) => Number.isFinite(Number(event?.time?.elapsed)))
      .slice()
      .sort((a, b) => (
        Number(a.time.elapsed || 0) - Number(b.time.elapsed || 0)
        || Number(a.time.extra || 0) - Number(b.time.extra || 0)
      ))[0];
    if (!firstGoal) return '';
    return eventBelongsToMatchSide(firstGoal, side) ? 'for' : 'against';
  };
  const fixtureGoalInfo = (fixture, side) => {
    const ownSide = fixtureSide(fixture, side);
    const homeGoals = fixtureScoreNumber(fixture?.goals?.home ?? fixture?.score_home);
    const awayGoals = fixtureScoreNumber(fixture?.goals?.away ?? fixture?.score_away);
    if (homeGoals === null || awayGoals === null) return null;
    const halfHome = fixtureScoreNumber(fixture?.score?.halftime?.home ?? fixture?.score_halftime_home);
    const halfAway = fixtureScoreNumber(fixture?.score?.halftime?.away ?? fixture?.score_halftime_away);
    const ownGoals = ownSide === 'away' ? awayGoals : homeGoals;
    const opponentGoals = ownSide === 'away' ? homeGoals : awayGoals;
    const ownHalfGoals = halfHome !== null && halfAway !== null ? (ownSide === 'away' ? halfAway : halfHome) : null;
    const opponentHalfGoals = halfHome !== null && halfAway !== null ? (ownSide === 'away' ? halfHome : halfAway) : null;
    const firstHalfGoals = halfHome !== null && halfAway !== null ? halfHome + halfAway : null;
    const secondHalfGoals = firstHalfGoals !== null ? Math.max(0, homeGoals + awayGoals - firstHalfGoals) : null;
    const ownSecondHalfGoals = ownHalfGoals !== null ? Math.max(0, ownGoals - ownHalfGoals) : null;
    const opponentSecondHalfGoals = opponentHalfGoals !== null ? Math.max(0, opponentGoals - opponentHalfGoals) : null;
    return {
      totalGoals: homeGoals + awayGoals,
      ownGoals,
      opponentGoals,
      btts: homeGoals > 0 && awayGoals > 0,
      ownHalfGoals,
      opponentHalfGoals,
      firstHalfGoals,
      secondHalfGoals,
      ownSecondHalfGoals,
      opponentSecondHalfGoals,
      firstGoalSide: firstGoalSideForFixture(fixture, side),
      halfScore: ownHalfGoals !== null && opponentHalfGoals !== null ? `${ownHalfGoals}-${opponentHalfGoals}` : null
    };
  };
  const fixtureCardCount = (fixture, side) => {
    const events = Array.isArray(fixture?.card_events) ? fixture.card_events : [];
    if (!events.length) return null;
    return events.filter((event) => eventBelongsToMatchSide(event, side)).length;
  };
  const mostFrequent = (values = []) => {
    const counts = new Map();
    values.filter(Boolean).forEach((value) => counts.set(value, (counts.get(value) || 0) + 1));
    return [...counts.entries()]
      .map(([label, count]) => ({ label, count }))
      .sort((a, b) => b.count - a.count || String(a.label).localeCompare(String(b.label), 'es'))[0] || null;
  };
  const thresholdStats = (rows, valueKey, thresholds = [.5, 1.5, 2.5, 3.5, 4.5]) => thresholds.map((threshold) => ({
    threshold,
    label: `+${String(threshold).replace('.', ',')} but${threshold >= 1.5 ? 's' : ''}`,
    count: rows.filter((row) => Number(row[valueKey]) > threshold).length,
    total: rows.length
  }));
  const recentTrendForSide = (side) => {
    const rows = recentRowsForSide(side).map((fixture) => fixtureGoalInfo(fixture, side)).filter(Boolean);
    const halftimeRows = rows.filter((row) => row.firstHalfGoals !== null && row.secondHalfGoals !== null);
    const firstHalfMost = halftimeRows.filter((row) => row.firstHalfGoals > row.secondHalfGoals).length;
    const secondHalfMost = halftimeRows.filter((row) => row.secondHalfGoals > row.firstHalfGoals).length;
    const equalHalf = halftimeRows.filter((row) => row.firstHalfGoals === row.secondHalfGoals).length;
    const halfOptions = [
      { label: '1re MT', count: firstHalfMost },
      { label: '2e MT', count: secondHalfMost },
      { label: 'Égalité', count: equalHalf }
    ].sort((a, b) => b.count - a.count);
    const cardRows = recentRowsForSide(side)
      .map((fixture) => fixtureCardCount(fixture, side))
      .filter((value) => value !== null);
    const cardTotal = cardRows.reduce((sum, value) => sum + Number(value || 0), 0);
    const halfScoreRows = rows.filter((row) => row.halfScore);
    const bestHalfScore = mostFrequent(halfScoreRows.map((row) => row.halfScore));
    return {
      side,
      available: rows.length > 0,
      count: rows.length,
      btts: rows.filter((row) => row.btts).length,
      cleanSheets: rows.filter((row) => Number(row.opponentGoals || 0) === 0).length,
      blankMatches: rows.filter((row) => Number(row.ownGoals || 0) === 0).length,
      halfAvailable: halftimeRows.length > 0,
      halfTotal: halftimeRows.length,
      bestHalf: halfOptions[0] || { label: '-', count: 0 },
      halfScoreAvailable: halfScoreRows.length > 0,
      halfScoreTotal: halfScoreRows.length,
      bestHalfScore,
      cardAvailable: cardRows.length > 0,
      cardTotal,
      cardMatches: cardRows.length,
      avgCards: cardRows.length ? cardTotal / cardRows.length : null,
      matchGoals: thresholdStats(rows, 'totalGoals'),
      teamGoals: thresholdStats(rows, 'ownGoals')
    };
  };
  const homeRecentTrend = recentTrendForSide('home');
  const awayRecentTrend = recentTrendForSide('away');
  const thresholdWidth = (item) => item.total ? Math.max(4, Math.round((item.count / item.total) * 100)) : 0;
  const trendPct = (count, total) => Math.max(0, Math.min(100, total ? Math.round((Number(count || 0) / total) * 100) : 0));
  const lineupPlayersForSide = (side) => {
    const lineup = side === 'home' ? homeLineup : awayLineup;
    return [
      ...(Array.isArray(lineup?.start_xi) ? lineup.start_xi : []),
      ...(Array.isArray(lineup?.substitutes) ? lineup.substitutes : [])
    ];
  };
  const topScorerForSide = (side) => {
    const lineup = side === 'home' ? homeLineup : awayLineup;
    const teamTopScorer = (Array.isArray(lineup?.top_scorers) ? lineup.top_scorers : [])
      .map((player) => ({
        name: player.name || '',
        photo: player.photo || '',
        goals: Number(player.goals || 0),
        assists: Number(player.assists || 0)
      }))
      .filter((player) => player.name && Number.isFinite(player.goals) && player.goals > 0)
      .sort((a, b) => b.goals - a.goals || b.assists - a.assists)[0];
    if (teamTopScorer) return teamTopScorer;

    return lineupPlayersForSide(side)
      .map((player) => ({
        name: player.name || '',
        photo: player.photo || '',
        goals: Number(player.goals || 0),
        assists: Number(player.assists || 0)
      }))
      .filter((player) => player.name && Number.isFinite(player.goals) && player.goals > 0)
      .sort((a, b) => b.goals - a.goals || b.assists - a.assists)[0] || null;
  };
  const homeTopScorer = topScorerForSide('home');
  const awayTopScorer = topScorerForSide('away');
  const playerPositionBaseShots = (position = '') => {
    const normalized = String(position || '').toLowerCase();
    if (normalized.includes('g')) return 0.1;
    if (normalized.includes('d')) return 0.45;
    if (normalized.includes('m')) return 0.95;
    if (normalized.includes('f') || normalized.includes('a')) return 1.65;
    return 0.8;
  };
  const playerShotRowsForSide = (side) => {
    const lineup = side === 'home' ? homeLineup : awayLineup;
    const topByName = new Map((Array.isArray(lineup?.top_scorers) ? lineup.top_scorers : []).map((player) => [
      normalizeName(player.name),
      player
    ]));
    const merged = new Map();
    lineupPlayersForSide(side)
      .filter((player) => {
        const name = String(player?.name || '').trim();
        return name && !/^(dom|ext)\s+(probable|banc)/i.test(name);
      })
      .forEach((player, index) => {
        const key = normalizeName(player.name) || `player-${index}`;
        const top = topByName.get(key) || {};
        const goals = Number(top.goals ?? player.goals ?? 0);
        const assists = Number(top.assists ?? player.assists ?? 0);
        const appearances = Number(top.appearances ?? player.appearances ?? 0);
        const base = playerPositionBaseShots(player.position);
        const goalBoost = goals > 0 ? Math.min(2.4, (goals / Math.max(appearances || 6, 1)) * 5.5) : 0;
        const assistBoost = assists > 0 ? Math.min(0.5, assists / Math.max(appearances || 8, 1)) : 0;
        const shots = Math.max(0.1, Math.min(4.8, base + goalBoost + assistBoost));
        merged.set(key, {
          name: player.name,
          photo: top.photo || player.photo || '',
          number: player.number || '',
          position: player.position || '',
          shots,
          shotsOnTarget: Math.max(0.1, shots * 0.42)
        });
      });
    (Array.isArray(lineup?.top_scorers) ? lineup.top_scorers : []).forEach((player, index) => {
      const key = normalizeName(player.name) || `scorer-${index}`;
      if (merged.has(key) || !player.name) return;
      const goals = Number(player.goals || 0);
      const appearances = Number(player.appearances || 0);
      const shots = Math.max(0.8, Math.min(4.8, 1.2 + (goals / Math.max(appearances || 6, 1)) * 5.5));
      merged.set(key, {
        name: player.name,
        photo: player.photo || '',
        number: '',
        position: '',
        shots,
        shotsOnTarget: Math.max(0.1, shots * 0.42)
      });
    });
    return [...merged.values()]
      .sort((a, b) => Number(b.shots || 0) - Number(a.shots || 0) || String(a.name).localeCompare(String(b.name), 'es'))
      .slice(0, 14);
  };
  const homePlayerShotRows = playerShotRowsForSide('home');
  const awayPlayerShotRows = playerShotRowsForSide('away');
  const hasPlayerShotRows = homePlayerShotRows.length || awayPlayerShotRows.length;
  const scenarioStatCount = (side, predicate, totalPredicate = () => true) => {
    const rows = recentRowsForSide(side).map((fixture) => fixtureGoalInfo(fixture, side)).filter(Boolean).filter(totalPredicate);
    return {
      count: rows.filter(predicate).length,
      total: rows.length
    };
  };
  const scenarioOutcome = (row) => {
    if (!row) return '';
    if (row.ownGoals > row.opponentGoals) return 'win';
    if (row.ownGoals === row.opponentGoals) return 'draw';
    return 'loss';
  };
  const secondHalfOutcome = (row) => {
    if (!row || row.ownSecondHalfGoals === null || row.opponentSecondHalfGoals === null) return '';
    if (row.ownSecondHalfGoals > row.opponentSecondHalfGoals) return 'win';
    if (row.ownSecondHalfGoals === row.opponentSecondHalfGoals) return 'draw';
    return 'loss';
  };
  const halftimeOutcome = (row) => {
    if (!row || row.ownHalfGoals === null || row.opponentHalfGoals === null) return '';
    if (row.ownHalfGoals > row.opponentHalfGoals) return 'win';
    if (row.ownHalfGoals === row.opponentHalfGoals) return 'draw';
    return 'loss';
  };
  const scenarioRows = [
    {
      label: 'Ouvre le score puis gagne',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'win', (row) => row.firstGoalSide === 'for'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'win', (row) => row.firstGoalSide === 'for')
    },
    {
      label: 'Ouvre le score puis match nul',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'draw', (row) => row.firstGoalSide === 'for'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'draw', (row) => row.firstGoalSide === 'for')
    },
    {
      label: 'Ouvre le score puis perd',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'loss', (row) => row.firstGoalSide === 'for'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'for' && scenarioOutcome(row) === 'loss', (row) => row.firstGoalSide === 'for')
    },
    {
      label: 'Gagne la 2ème mi-temps',
      home: scenarioStatCount('home', (row) => secondHalfOutcome(row) === 'win', (row) => secondHalfOutcome(row)),
      away: scenarioStatCount('away', (row) => secondHalfOutcome(row) === 'win', (row) => secondHalfOutcome(row))
    },
    {
      label: 'Match nul la 2ème mi-temps',
      home: scenarioStatCount('home', (row) => secondHalfOutcome(row) === 'draw', (row) => secondHalfOutcome(row)),
      away: scenarioStatCount('away', (row) => secondHalfOutcome(row) === 'draw', (row) => secondHalfOutcome(row))
    },
    {
      label: 'Perd la 2ème mi-temps',
      home: scenarioStatCount('home', (row) => secondHalfOutcome(row) === 'loss', (row) => secondHalfOutcome(row)),
      away: scenarioStatCount('away', (row) => secondHalfOutcome(row) === 'loss', (row) => secondHalfOutcome(row))
    },
    {
      label: 'Encaisse en premier puis gagne',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'win', (row) => row.firstGoalSide === 'against'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'win', (row) => row.firstGoalSide === 'against')
    },
    {
      label: 'Encaisse en premier puis match nul',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'draw', (row) => row.firstGoalSide === 'against'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'draw', (row) => row.firstGoalSide === 'against')
    },
    {
      label: 'Encaisse en premier puis perd',
      home: scenarioStatCount('home', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'loss', (row) => row.firstGoalSide === 'against'),
      away: scenarioStatCount('away', (row) => row.firstGoalSide === 'against' && scenarioOutcome(row) === 'loss', (row) => row.firstGoalSide === 'against')
    },
    {
      label: 'Nul à la mi-temps puis gagne',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'draw'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'draw')
    },
    {
      label: 'Nul à la mi-temps puis match nul',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'draw', (row) => halftimeOutcome(row) === 'draw'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'draw', (row) => halftimeOutcome(row) === 'draw')
    },
    {
      label: 'Nul à la mi-temps puis perd',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'loss', (row) => halftimeOutcome(row) === 'draw'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'draw' && scenarioOutcome(row) === 'loss', (row) => halftimeOutcome(row) === 'draw')
    },
    {
      label: 'Mène à la mi-temps puis gagne',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'win' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'win'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'win' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'win')
    },
    {
      label: 'Gagne la 1ère mi-temps puis perd le match',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'win' && scenarioOutcome(row) === 'loss', (row) => halftimeOutcome(row) === 'win'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'win' && scenarioOutcome(row) === 'loss', (row) => halftimeOutcome(row) === 'win')
    },
    {
      label: 'Perd à la mi-temps puis fait match nul',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'loss' && scenarioOutcome(row) === 'draw', (row) => halftimeOutcome(row) === 'loss'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'loss' && scenarioOutcome(row) === 'draw', (row) => halftimeOutcome(row) === 'loss')
    },
    {
      label: 'Perd à la mi-temps puis gagne',
      home: scenarioStatCount('home', (row) => halftimeOutcome(row) === 'loss' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'loss'),
      away: scenarioStatCount('away', (row) => halftimeOutcome(row) === 'loss' && scenarioOutcome(row) === 'win', (row) => halftimeOutcome(row) === 'loss')
    }
  ].filter((row) => (row.home.total || row.away.total));
  const scenarioFraction = (value) => value && value.total ? `${value.count}/${value.total}` : '-';
  const hasCardTrend = homeRecentTrend.cardAvailable || awayRecentTrend.cardAvailable;
  const hasHalfScoreTrend = homeRecentTrend.halfScoreAvailable || awayRecentTrend.halfScoreAvailable;
  const showPreMatchStatTools = !shouldUseRealStats && (homeRecentTrend.available || awayRecentTrend.available || homeTopScorer || awayTopScorer || hasPlayerShotRows || hasCardTrend || hasHalfScoreTrend || scenarioRows.length);
  const formCards = (side) => (Array.isArray(recentFixtureSource[side]) ? recentFixtureSource[side] : [])
    .slice(0, 5)
    .map((fixture) => {
      const ownSide = fixtureSide(fixture, side);
      const opponentSide = ownSide === 'home' ? 'away' : 'home';
      const ownGoals = ownSide === 'home' ? fixture?.goals?.home : fixture?.goals?.away;
      const opponentGoals = ownSide === 'home' ? fixture?.goals?.away : fixture?.goals?.home;
      const result = Number(ownGoals) > Number(opponentGoals) ? 'V' : (Number(ownGoals) === Number(opponentGoals) ? 'N' : 'D');
      return {
        result,
        score: Number.isFinite(Number(ownGoals)) && Number.isFinite(Number(opponentGoals)) ? `${ownGoals}-${opponentGoals}` : '?',
        logo: fixture?.teams?.[opponentSide]?.logo || '',
        name: fixture?.teams?.[opponentSide]?.name || 'Adversaire'
      };
    });
  const fallbackFormCards = (form) => String(form?.form || '')
    .split('-')
    .filter(Boolean)
    .slice(0, 5)
    .map((result) => ({ result, score: '?', logo: '', name: 'Adversaire' }));
  const homeFormCards = formCards('home').length ? formCards('home') : fallbackFormCards(recentHome);
  const awayFormCards = formCards('away').length ? formCards('away') : fallbackFormCards(recentAway);
  const fixtureDate = (fixture) => {
    const dateValue = fixture?.fixture?.date || fixture?.date;
    const date = dateValue ? new Date(dateValue) : null;
    return date && !Number.isNaN(date.getTime())
      ? date.toLocaleDateString('es-ES', { day: '2-digit', month: '2-digit', year: '2-digit' })
      : '--/--/--';
  };
  const fixtureCompetition = (fixture) => fixture?.league?.name || fixture?.league_name || 'Compétition';
  const fixtureLogo = (fixture) => fixture?.league?.logo || fixture?.competition_logo || '';
  const fixtureStatus = (fixture) => fixture?.fixture?.status?.short || fixture?.status || 'FT';
  const h2hRows = h2hSource.slice(0, 8);
  const homeRecentRows = Array.isArray(recentFixtureSource.home) ? recentFixtureSource.home.slice(0, 8) : [];
  const awayRecentRows = Array.isArray(recentFixtureSource.away) ? recentFixtureSource.away.slice(0, 8) : [];
  const defaultFormPanel = h2hRows.length ? 'h2h' : (homeRecentRows.length ? 'home' : 'away');
  const historyPanels = [
    {
      key: 'home',
      title: `Derniers matchs de ${safeMatch.home_team || 'Domicile'}`,
      subtitle: `Forme récente de ${safeMatch.home_team || 'l’équipe domicile'}`,
      rows: homeRecentRows
    },
    {
      key: 'h2h',
      title: 'Derniers matchs',
      subtitle: 'Confrontations directes entre les deux équipes',
      rows: h2hRows
    },
    {
      key: 'away',
      title: `Derniers matchs de ${safeMatch.away_team || 'Extérieur'}`,
      subtitle: `Forme récente de ${safeMatch.away_team || 'l’équipe extérieur'}`,
      rows: awayRecentRows
    }
  ];
  const compactMatchDay = (() => {
    if (!kickoffDate || Number.isNaN(kickoffDate.getTime())) return 'Hoy';
    const today = new Date();
    if (kickoffDate.toDateString() === today.toDateString()) return "Hoy";
    return kickoffDate.toLocaleDateString('es-ES', { day: 'numeric', month: 'short' }).replace(/\.$/, '');
  })();
  const frenchMatchLabel = (value) => {
    const text = String(value || '').trim();
    if (!text) return '';
    const normalized = text.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
    if (['a venir', 'avenir', 'not started', 'non commence', 'ns', 'tbd'].includes(normalized)) return 'À venir';
    if (['live', 'en direct', '1h', '2h', 'ht'].includes(normalized)) return 'En direct';
    if (['finished', 'termine', 'ft'].includes(normalized)) return 'Terminé';
    return text;
  };
  const competitionDetail = [safeMatch.competition_name || 'Compétition', frenchMatchLabel(safeMatch.round || safeMatch.stage || safeMatch.status || safeMatch.status_short)].filter(Boolean).join(', ');
  const hasOddsLine = Boolean(matchOdds && (matchOdds.home || matchOdds.draw || matchOdds.away));
  const scoreScenarioMarketProbabilities = (() => {
    if (!matchOdds || !matchOdds.home || !matchOdds.away) return null;
    const rawHome = Number(matchOdds.home) > 1 ? 1 / Number(matchOdds.home) : 0;
    const rawDraw = Number(matchOdds.draw) > 1 ? 1 / Number(matchOdds.draw) : 0;
    const rawAway = Number(matchOdds.away) > 1 ? 1 / Number(matchOdds.away) : 0;
    const total = rawHome + rawDraw + rawAway;
    if (!total) return null;
    return { home: rawHome / total, draw: rawDraw / total, away: rawAway / total };
  })();
  const scoreScenarioMarketFavorite = scoreScenarioMarketProbabilities
    ? (scoreScenarioMarketProbabilities.home > scoreScenarioMarketProbabilities.away ? 'home' : 'away')
    : null;
  const scoreScenarioMarketGap = scoreScenarioMarketProbabilities
    ? Math.abs(scoreScenarioMarketProbabilities.home - scoreScenarioMarketProbabilities.away)
    : 0;
  const scoreScenarioNeedsMarketCorrection = Boolean(
    scoreScenarioMarketFavorite
    && scoreScenarioMarketGap >= .18
    && scoreScenarioItems.slice(0, 3).some((scenario) => {
      const home = Number(scenario.home ?? String(scenario.score || '').split('-')[0]);
      const away = Number(scenario.away ?? String(scenario.score || '').split('-')[1]);
      if (!Number.isFinite(home) || !Number.isFinite(away)) return false;
      return scoreScenarioMarketFavorite === 'away' ? home > away : away > home;
    })
  );
  const correctedScoreCandidates = (() => {
    if (!scoreScenarioNeedsMarketCorrection) return [];
    const favoriteProbability = scoreScenarioMarketFavorite === 'home'
      ? scoreScenarioMarketProbabilities.home
      : scoreScenarioMarketProbabilities.away;
    const favoriteLambda = favoriteProbability >= .72 ? 2.35 : 1.85;
    const underdogLambda = favoriteProbability >= .72 ? .62 : .88;
    const homeLambda = scoreScenarioMarketFavorite === 'home' ? favoriteLambda : underdogLambda;
    const awayLambda = scoreScenarioMarketFavorite === 'away' ? favoriteLambda : underdogLambda;
    const factorial = (value) => {
      let total = 1;
      for (let index = 2; index <= value; index += 1) total *= index;
      return total;
    };
    const poisson = (lambda, goals) => (
      Math.exp(-lambda) * (lambda ** goals) / factorial(goals)
    );
    const rows = [];
    for (let home = 0; home <= 5; home += 1) {
      for (let away = 0; away <= 5; away += 1) {
        if (scoreScenarioMarketFavorite === 'away' && home > away) continue;
        if (scoreScenarioMarketFavorite === 'home' && away > home) continue;
        const probability = poisson(homeLambda, home) * poisson(awayLambda, away) * 100;
        rows.push({
          score: `${home}-${away}`,
          home,
          away,
          probability: Math.round(probability * 10) / 10,
          risk_label: 'Lecture plausible',
          market_corrected: true
        });
      }
    }
    return rows.sort((a, b) => b.probability - a.probability);
  })();
  const scoreScenarioPreview = (correctedScoreCandidates.length ? correctedScoreCandidates : scoreScenarioItems).slice(0, 3);
  const scoreScenarioPlaceholders = [
    { score: '2-0', probability: 21.7, risk_label: 'Lecture plausible' },
    { score: '1-0', probability: 16.4, risk_label: 'Lecture prudente' },
    { score: '2-1', probability: 13.8, risk_label: 'Alternative nette' }
  ];
  const exactScoreCards = (scoreScenarioPreview.length ? scoreScenarioPreview : scoreScenarioPlaceholders).slice(0, 3);
  while (exactScoreCards.length < 3) exactScoreCards.push(scoreScenarioPlaceholders[exactScoreCards.length]);
  const exactScoreTitle = (index) => ['1er score favori du modèle', '2e score favori du modèle', '3e score favori du modèle'][index] || `${index + 1}e score favori du modèle`;
  const exactScoreValue = (scenario, index) => pageLocked ? scoreScenarioPlaceholders[index].score : (scenario.score || scoreScenarioPlaceholders[index].score);
  const exactScoreProbability = (scenario, index) => pageLocked
    ? scoreScenarioPlaceholders[index].probability
    : Number(scenario.probability || scoreScenarioPlaceholders[index].probability || 0);
  const exactScoreRisk = (scenario, index) => pageLocked
    ? scoreScenarioPlaceholders[index].risk_label
    : (scenario.risk_label || scoreScenarioPlaceholders[index].risk_label || 'Lecture plausible');
  const clampPercent = (value, fallback = 55) => Math.max(1, Math.min(99, Math.round(Number.isFinite(Number(value)) ? Number(value) : fallback)));
  const oneDecimalFr = (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed.toFixed(1).replace('.', ',') : '-';
  };
  const scoreMatrixMaxGoal = 5;
  const scoreMatrixLabels = Array.from({ length: scoreMatrixMaxGoal + 1 }, (_, index) => index);
  const scoreMatrixFactorial = (value) => {
    let total = 1;
    for (let index = 2; index <= value; index += 1) total *= index;
    return total;
  };
  const scoreMatrixPoisson = (lambda, goals) => (
    Math.exp(-Math.max(0.05, Number(lambda) || 1.2))
      * (Math.max(0.05, Number(lambda) || 1.2) ** goals)
      / scoreMatrixFactorial(goals)
  );
  const scoreMatrixCandidateSource = (() => {
    if (!scoreScenarioData || pageAnalysisLoading) return [];
    if (correctedScoreCandidates.length) return correctedScoreCandidates;
    if (Array.isArray(scoreScenarioData.all_candidates) && scoreScenarioData.all_candidates.length) return scoreScenarioData.all_candidates;
    if (Array.isArray(scoreScenarioData.matrix) && scoreScenarioData.matrix.length) return scoreScenarioData.matrix;
    return [];
  })();
  const normalizeScoreMatrixCandidate = (candidate) => {
    const parsedHome = Number(candidate && candidate.home);
    const parsedAway = Number(candidate && candidate.away);
    const scoreParts = String(candidate && candidate.score || '').match(/^(\d+)\s*-\s*(\d+)$/);
    const homeGoals = Number.isFinite(parsedHome) ? parsedHome : (scoreParts ? Number(scoreParts[1]) : null);
    const awayGoals = Number.isFinite(parsedAway) ? parsedAway : (scoreParts ? Number(scoreParts[2]) : null);
    if (!Number.isFinite(homeGoals) || !Number.isFinite(awayGoals)) return null;
    return {
      home: homeGoals,
      away: awayGoals,
      score: `${homeGoals}-${awayGoals}`,
      probability: Number(candidate && candidate.probability || 0),
      risk_label: candidate && candidate.risk_label || ''
    };
  };
  const buildScoreMatrixCandidates = () => {
    const normalized = scoreMatrixCandidateSource
      .map(normalizeScoreMatrixCandidate)
      .filter((candidate) => (
        candidate
        && candidate.home >= 0
        && candidate.away >= 0
        && candidate.home <= scoreMatrixMaxGoal
        && candidate.away <= scoreMatrixMaxGoal
      ));
    if (!pageLocked && normalized.length >= 12) return normalized;
    const homeLambda = pageLocked ? 1.45 : safeNumber(estimatedHomeXg, avgFor(recentHome) || 1.35);
    const awayLambda = pageLocked ? 0.95 : safeNumber(estimatedAwayXg, avgFor(recentAway) || 1.05);
    const generated = [];
    for (let home = 0; home <= scoreMatrixMaxGoal; home += 1) {
      for (let away = 0; away <= scoreMatrixMaxGoal; away += 1) {
        generated.push({
          home,
          away,
          score: `${home}-${away}`,
          probability: Math.round(scoreMatrixPoisson(homeLambda, home) * scoreMatrixPoisson(awayLambda, away) * 1000) / 10,
          risk_label: ''
        });
      }
    }
    return generated;
  };
  const scoreMatrixCandidates = buildScoreMatrixCandidates();
  const scoreMatrixCandidateMap = new Map(scoreMatrixCandidates.map((candidate) => [`${candidate.home}-${candidate.away}`, candidate]));
  exactScoreCards.forEach((scenario, index) => {
    const scoreParts = String(exactScoreValue(scenario, index) || '').match(/^(\d+)\s*-\s*(\d+)$/);
    if (!scoreParts) return;
    const home = Number(scoreParts[1]);
    const away = Number(scoreParts[2]);
    if (!Number.isFinite(home) || !Number.isFinite(away) || home > scoreMatrixMaxGoal || away > scoreMatrixMaxGoal) return;
    scoreMatrixCandidateMap.set(`${home}-${away}`, {
      ...(scoreMatrixCandidateMap.get(`${home}-${away}`) || {}),
      home,
      away,
      score: `${home}-${away}`,
      probability: exactScoreProbability(scenario, index),
      risk_label: exactScoreRisk(scenario, index)
    });
  });
  const scoreMatrixFeaturedScores = new Set(exactScoreCards.map((scenario, index) => exactScoreValue(scenario, index)));
  const scoreMatrixMaxProbability = Math.max(1, ...Array.from(scoreMatrixCandidateMap.values()).map((candidate) => Number(candidate.probability || 0)));
  const scoreMatrixPercent = (value) => {
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) return '-';
    if (parsed > 0 && parsed < 0.1) return '<0,1';
    return oneDecimalFr(parsed);
  };
  const scoreMatrixRows = [...scoreMatrixLabels].reverse().map((home) => ({
    home,
    cells: scoreMatrixLabels.map((away) => {
      const candidate = scoreMatrixCandidateMap.get(`${home}-${away}`) || { home, away, score: `${home}-${away}`, probability: 0 };
      const intensity = Math.max(1, Math.min(5, Math.ceil((Number(candidate.probability || 0) / scoreMatrixMaxProbability) * 5)));
      return {
        ...candidate,
        intensity,
        featured: scoreMatrixFeaturedScores.has(candidate.score)
      };
    })
  }));
  const oddsFr = (value) => {
    const parsed = Number(value && typeof value === 'object' ? value.odd : value);
    return Number.isFinite(parsed) && parsed > 1 ? parsed.toFixed(2) : '-';
  };
  const generalStatOddNumber = (row) => {
    const parsed = Number(row && row.odd && typeof row.odd === 'object' ? row.odd.odd : row && row.odd);
    return Number.isFinite(parsed) ? parsed : null;
  };
  const generalStatLocked = (row) => {
    const odd = generalStatOddNumber(row);
    return Boolean(pageAuthLocked || (pageLocked && odd && odd > freeLimit));
  };
  const impliedFromOdd = (value, fallback = 50) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 1 ? clampPercent(100 / parsed, fallback) : clampPercent(fallback, fallback);
  };
  const totalExpectedGoals = Math.max(0, safeNumber(estimatedHomeXg, avgFor(recentHome)) + safeNumber(estimatedAwayXg, avgFor(recentAway)));
  const homeResultProb = matchOdds && matchOdds.home ? impliedFromOdd(matchOdds.home, 42) : clampPercent(44 + ((pointsPerMatch(recentHome) - pointsPerMatch(recentAway)) * 9), 46);
  const drawResultProb = matchOdds && matchOdds.draw ? impliedFromOdd(matchOdds.draw, 28) : clampPercent(30 - Math.abs(pointsPerMatch(recentHome) - pointsPerMatch(recentAway)) * 5, 28);
  const awayResultProb = matchOdds && matchOdds.away ? impliedFromOdd(matchOdds.away, 42) : clampPercent(44 + ((pointsPerMatch(recentAway) - pointsPerMatch(recentHome)) * 9), 46);
  const hasGeneralStatOdd = (odd) => {
    const parsed = Number(odd && typeof odd === 'object' ? odd.odd : odd);
    return Number.isFinite(parsed) && parsed > 1;
  };
  const bestGeneralCandidate = (candidates = []) => candidates
    .filter((candidate) => candidate && hasGeneralStatOdd(candidate.odd))
    .sort((a, b) => Number(b.probability || 0) - Number(a.probability || 0))[0] || null;
  const bttsProbability = clampPercent(
    ((Math.min(avgFor(recentHome), avgFor(recentAway)) * 22)
      + ((avgAgainst(recentHome) + avgAgainst(recentAway)) * 12)
      + (safePreMatchSummary?.h2h?.bttsRate || 48)) / 2,
    54
  );
  const resultRow = bestGeneralCandidate([
    {
      label: `${safeMatch.home_team || 'Domicile'} gagne`,
      probability: homeResultProb,
      odd: safeGeneralStatsOdds.resultHome || matchOdds?.home,
      logo: safeMatch.home_logo
    },
    {
      label: 'Match nul',
      probability: drawResultProb,
      odd: safeGeneralStatsOdds.resultDraw || matchOdds?.draw
    },
    {
      label: `${safeMatch.away_team || 'Extérieur'} gagne`,
      probability: awayResultProb,
      odd: safeGeneralStatsOdds.resultAway || matchOdds?.away,
      logo: safeMatch.away_logo
    }
  ]);
  const halfTimeRow = bestGeneralCandidate([
    {
      label: `${safeMatch.home_team || 'Domicile'} mène à la mi-temps`,
      probability: clampPercent(homeResultProb * .62, 38),
      odd: safeGeneralStatsOdds.halfTimeHome,
      logo: safeMatch.home_logo
    },
    {
      label: 'Nul à la mi-temps',
      probability: clampPercent(37 + (drawResultProb * .22), 43),
      odd: safeGeneralStatsOdds.halfTimeDraw
    },
    {
      label: `${safeMatch.away_team || 'Extérieur'} mène à la mi-temps`,
      probability: clampPercent(awayResultProb * .62, 38),
      odd: safeGeneralStatsOdds.halfTimeAway,
      logo: safeMatch.away_logo
    }
  ]);
  const bttsRow = bestGeneralCandidate([
    {
      label: 'Les deux équipes marquent',
      probability: bttsProbability,
      odd: safeGeneralStatsOdds.bttsYes
    },
    {
      label: 'Au moins une équipe ne marque pas',
      probability: clampPercent(100 - bttsProbability, 46),
      odd: safeGeneralStatsOdds.bttsNo
    }
  ]);
  const firstGoalRow = bestGeneralCandidate([
    {
      label: `${safeMatch.home_team || 'Domicile'} marque en premier`,
      probability: clampPercent(homeResultProb + 8, 58),
      odd: safeGeneralStatsOdds.firstGoalHome,
      logo: safeMatch.home_logo
    },
    {
      label: `${safeMatch.away_team || 'Extérieur'} marque en premier`,
      probability: clampPercent(awayResultProb + 8, 58),
      odd: safeGeneralStatsOdds.firstGoalAway,
      logo: safeMatch.away_logo
    }
  ]);
  const winHalfRow = bestGeneralCandidate([
    {
      label: `${safeMatch.home_team || 'Domicile'} gagne au moins une mi-temps`,
      probability: clampPercent(homeResultProb + 12, 62),
      odd: safeGeneralStatsOdds.winEitherHalfHome,
      logo: safeMatch.home_logo
    },
    {
      label: `${safeMatch.away_team || 'Extérieur'} gagne au moins une mi-temps`,
      probability: clampPercent(awayResultProb + 12, 62),
      odd: safeGeneralStatsOdds.winEitherHalfAway,
      logo: safeMatch.away_logo
    }
  ]);
  const doubleChanceRow = bestGeneralCandidate([
    {
      label: `${safeMatch.home_team || 'Domicile'} ou nul`,
      probability: clampPercent(homeResultProb + Math.round(drawResultProb * .72), 70),
      odd: safeGeneralStatsOdds.doubleChanceHomeDraw
    },
    {
      label: `${safeMatch.away_team || 'Extérieur'} ou nul`,
      probability: clampPercent(awayResultProb + Math.round(drawResultProb * .72), 70),
      odd: safeGeneralStatsOdds.doubleChanceAwayDraw
    }
  ]);
  const neoGeneralStats = [
    resultRow && { category: 'Résultats', ...resultRow },
    halfTimeRow && { category: 'Mi-temps résultats', ...halfTimeRow },
    bttsRow && { category: 'But des 2 équipes', ...bttsRow },
    firstGoalRow && { category: 'Premier but', ...firstGoalRow },
    winHalfRow && { category: 'Gagne au moins 1 mi-temps', ...winHalfRow },
    doubleChanceRow && { category: 'Double chance', ...doubleChanceRow }
  ].filter((row) => row && hasGeneralStatOdd(row.odd));
  const resultProbabilityRows = [
    { label: safeMatch.home_team || 'Domicile', type: 'home', logo: safeMatch.home_logo, value: homeResultProb },
    { label: 'Match nul', type: 'draw', logo: '', value: drawResultProb },
    { label: safeMatch.away_team || 'Extérieur', type: 'away', logo: safeMatch.away_logo, value: awayResultProb }
  ];
  const projectedShots = (form, side = 'home') => {
    const goalsFor = avgFor(form);
    const goalsAgainst = avgAgainst(form);
    const base = goalsFor || goalsAgainst ? (goalsFor * 3.45) + (goalsAgainst * 1.05) + 1.1 : null;
    const marketBias = (side === 'home' ? homeResultProb - awayResultProb : awayResultProb - homeResultProb) / 18;
    return base === null ? null : Math.max(3.2, base + marketBias);
  };
  const projectedTotalShotsHome = projectedShots(recentHome, 'home');
  const projectedTotalShotsAway = projectedShots(recentAway, 'away');
  const projectedPossessionHome = recentHome && recentAway ? Math.max(20, Math.min(72, 50 + ((pointsPerMatch(recentHome) - pointsPerMatch(recentAway)) * 7) + ((homeResultProb - awayResultProb) / 7))) : null;
  const projectedPossessionAway = projectedPossessionHome !== null ? Math.max(20, Math.min(72, 100 - projectedPossessionHome)) : null;
  const decisiveSituationRows = [
    metricPair('Tirs dans la surface', projectedTotalShotsHome ? projectedTotalShotsHome * .48 : null, projectedTotalShotsAway ? projectedTotalShotsAway * .48 : null),
    metricPair('Tirs hors surface', projectedTotalShotsHome ? projectedTotalShotsHome * .52 : null, projectedTotalShotsAway ? projectedTotalShotsAway * .52 : null),
    metricPair('Tirs contrés', projectedTotalShotsHome ? projectedTotalShotsHome * .32 : null, projectedTotalShotsAway ? projectedTotalShotsAway * .32 : null),
    metricPair('Arrêts du gardien', avgAgainst(recentHome) ? Math.max(.2, avgAgainst(recentHome) * 1.85) : null, avgAgainst(recentAway) ? Math.max(.2, avgAgainst(recentAway) * 1.85) : null)
  ];
  const highlightRows = [
    metricPair('Clean sheets', homeRecentTrend.cleanSheets, awayRecentTrend.cleanSheets),
    metricPair('Matchs sans marquer', homeRecentTrend.blankMatches, awayRecentTrend.blankMatches),
    metricPair('Penalties tirés', 0, 0),
    metricPair('Penalties marqués', 0, 0),
    metricPair('Penalties ratés', 0, 0)
  ];
  const matchManagementRows = [
    metricPair('Passes totales', projectedPossessionHome !== null ? projectedPossessionHome * 8.8 : null, projectedPossessionAway !== null ? projectedPossessionAway * 8.8 : null),
    metricPair('Passes réussies', projectedPossessionHome !== null ? projectedPossessionHome * 7.7 : null, projectedPossessionAway !== null ? projectedPossessionAway * 7.7 : null),
    metricPair('Précision des passes (%)', projectedPossessionHome !== null ? Math.max(38, Math.min(92, projectedPossessionHome + 24)) : null, projectedPossessionAway !== null ? Math.max(38, Math.min(92, projectedPossessionAway + 24)) : null, { suffix: '%' }),
    metricPair('Fautes commises', 8 + (100 - (projectedPossessionHome || 50)) / 14, 8 + (100 - (projectedPossessionAway || 50)) / 14),
    metricPair('Hors-jeu', avgFor(recentHome) ? Math.max(.2, avgFor(recentHome) * .62) : null, avgFor(recentAway) ? Math.max(.2, avgFor(recentAway) * .62) : null),
    metricPair('Cartons jaunes', homeRecentTrend.cardAvailable ? homeRecentTrend.avgCards : 1.2, awayRecentTrend.cardAvailable ? awayRecentTrend.avgCards : 1.2),
    metricPair('Cartons rouges', .1, .1)
  ];
%>

<main class="app-main analysis-layout analysis-page-v2 analysis-zonestat-detail" data-analysis-page data-analysis-loading="<%= pageAnalysisLoading ? 'true' : 'false' %>" data-analysis-url="<%= analysisUrl %>">
  <section class="analysis-v2-match">
    <div class="analysis-v2-topline">
      <span class="analysis-v2-competition-title"><i aria-hidden="true">🏆</i><%= safeMatch.competition_name || 'Compétition' %></span>
      <a class="analysis-v2-close" href="<%= matchBackHref %>">Fermer</a>
    </div>

    <div class="analysis-v2-scoreboard">
      <div class="analysis-v2-team">
        <% if (safeMatch.home_logo) { %>
          <img src="<%= safeMatch.home_logo %>" alt="">
        <% } else { %>
          <span class="team-logo"><%= initials(safeMatch.home_team) %></span>
        <% } %>
        <strong><%= safeMatch.home_team || 'Équipe domicile' %></strong>
        <form class="team-favorite-form" method="post" action="/favoris">
          <input type="hidden" name="type" value="team">
          <input type="hidden" name="external_id" value="<%= safeMatch.home_team_id || safeMatch.home_team || '' %>">
          <input type="hidden" name="team_id" value="<%= safeMatch.home_team_id || '' %>">
          <input type="hidden" name="label" value="<%= safeMatch.home_team || '' %>">
          <input type="hidden" name="logo" value="<%= safeMatch.home_logo || '' %>">
          <button type="submit">Suivre l’équipe</button>
        </form>
      </div>

      <div class="analysis-v2-score">
        <span class="analysis-v2-watermark" aria-hidden="true">TOPSTATS.ES</span>
        <% if (hasScore) { %>
          <strong><%= safeMatch.score_home %> - <%= safeMatch.score_away %></strong>
          <span>Score</span>
        <% } else { %>
          <strong><%= formatTime(safeMatch.kickoff_at) %></strong>
          <span><%= compactMatchDay %></span>
        <% } %>
      </div>

      <div class="analysis-v2-team">
        <% if (safeMatch.away_logo) { %>
          <img src="<%= safeMatch.away_logo %>" alt="">
        <% } else { %>
          <span class="team-logo"><%= initials(safeMatch.away_team) %></span>
        <% } %>
        <strong><%= safeMatch.away_team || 'Équipe extérieur' %></strong>
        <form class="team-favorite-form" method="post" action="/favoris">
          <input type="hidden" name="type" value="team">
          <input type="hidden" name="external_id" value="<%= safeMatch.away_team_id || safeMatch.away_team || '' %>">
          <input type="hidden" name="team_id" value="<%= safeMatch.away_team_id || '' %>">
          <input type="hidden" name="label" value="<%= safeMatch.away_team || '' %>">
          <input type="hidden" name="logo" value="<%= safeMatch.away_logo || '' %>">
          <button type="submit">Suivre l’équipe</button>
        </form>
      </div>
    </div>

    <nav class="analysis-v2-tabs" aria-label="Navigation du match">
      <a class="is-active" href="#resume" aria-selected="true">Résumé</a>
      <a href="#probabilites" aria-selected="false"><span aria-hidden="true">⚡</span> Probabilités</a>
      <a href="#stats" aria-selected="false">Statistiques</a>
      <a href="#compos" aria-selected="false">Compositions</a>
      <a href="#forme" aria-selected="false">Forme récente</a>
      <a href="#classement" aria-selected="false">Classement</a>
    </nav>

    <div class="analysis-v2-info-row">
      <span>MAJ <strong><%= formatDateTime(analysisUpdatedAt) %></strong></span>
      <% if (mainRecommendation && mainRecommendation.bookmaker) { %>
        <span>Cote lue chez <strong><%= mainRecommendation.bookmaker %></strong></span>
      <% } %>
    </div>

    <div class="analysis-v2-quality-panel">
      <div>
        <span>Qualité des sources disponibles pour ce match</span>
        <strong><%= qualityScore %>%</strong>
      </div>
      <div class="analysis-v2-quality-track" aria-hidden="true">
        <i style="width: <%= qualityScore %>%"></i>
      </div>
      <p><%= quality ? quality.label : 'Données limitées' %>. TopStats ajuste la confiance selon les informations réellement disponibles avant le match.</p>
    </div>

    <% if (pageAnalysisLoading) { %>
      <div class="analysis-v2-loading-card" data-analysis-loading-box>
        <span></span>
        <div>
          <strong>Cargando información...</strong>
          <p>TopStats récupère les statistiques, les cotes et les signaux pré-match. La page se mettra à jour automatiquement.</p>
        </div>
      </div>
    <% } %>
  </section>

  <section class="analysis-v2-picks-section analysis-v2-tab-panel is-active" id="resume" data-analysis-panel="resume">
    <div class="analysis-v2-section-title">
      <div>
        <p class="eyebrow"><%= isFinishedMatchPage ? 'Resumen del partido' : 'Pronósticos del partido' %></p>
        <h1><%= isFinishedMatchPage ? 'Stats réelles de' : 'Ce que TopStats retient pour' %> <%= safeMatch.home_team || 'Équipe domicile' %> - <%= safeMatch.away_team || 'Équipe extérieur' %></h1>
      </div>
    </div>

    <article class="zs-competition-card">
      <span class="zs-competition-icon" aria-hidden="true">🏆</span>
      <strong><%= competitionDetail || 'Compétition' %></strong>
    </article>

    <% if (!isFinishedMatchPage) { %>
      <article class="zs-odds-card">
        <div class="zs-card-head">
          <h2>Les cotes du match</h2>
          <span><%= matchOdds && matchOdds.bookmaker ? matchOdds.bookmaker : 'Cotes' %></span>
        </div>
        <div class="zs-odds-grid">
          <div><span>1</span><strong><%= matchOdds && matchOdds.home ? Number(matchOdds.home).toFixed(2) : '-' %></strong></div>
          <div><span>X</span><strong><%= matchOdds && matchOdds.draw ? Number(matchOdds.draw).toFixed(2) : '-' %></strong></div>
          <div><span>2</span><strong><%= matchOdds && matchOdds.away ? Number(matchOdds.away).toFixed(2) : '-' %></strong></div>
        </div>
      </article>
    <% } %>

    <% if (!isFinishedMatchPage) { %>
      <article class="zs-top-confidence-card <%= strongestRecommendationLocked ? 'is-locked' : '' %> <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
        <div class="zs-top-confidence-content">
          <p>Plus grosse confiance sur ce match</p>
          <strong><%= strongestRecommendation ? strongestRecommendation.title : 'Ningún consejo IA validado por ahora' %></strong>
          <div class="zs-top-confidence-badges">
            <span>
              <small>Confiance</small>
              <b><%= strongestRecommendation ? (strongestRecommendation.confidence || strongestRecommendation.estimated_probability || '-') : '-' %>%</b>
            </span>
            <% if (strongestRecommendationOdd) { %>
              <span>
                <small>Cote</small>
                <b><%= strongestRecommendationOdd.toFixed(2) %></b>
                <% if (strongestRecommendation.bookmaker) { %>
                  <em><%= strongestRecommendation.bookmaker %></em>
                <% } %>
              </span>
            <% } %>
          </div>
        </div>
        <% if (strongestRecommendationLocked) { %>
          <div class="zs-top-confidence-lock">
            <div>
              <% if (pageAuthLocked) { %>
                <strong><%= lockedAdviceCopy %></strong>
                <span>Inicia sesión para ver la mayor confianza generada por TopStats en este partido.</span>
              <% } else { %>
                <strong>Grosse confiance PRO</strong>
                <span>La meilleure confiance générée par TopStats dépasse la cote de <%= freeLimit.toFixed(2) %> et est réservée aux abonnés PRO.</span>
              <% } %>
            </div>
            <a href="<%= lockedAdviceHref %>"><%= lockedAdviceAction %></a>
          </div>
        <% } %>
      </article>
    <% } %>

    <article class="zs-vote-card" data-match-vote data-match-id="<%= safeMatch.id || safeMatch.api_fixture_id || '' %>">
      <div class="zs-card-head zs-vote-head">
        <div>
          <span class="zs-vote-icon" aria-hidden="true">♕</span>
          <h2>Votez pour le gagnant</h2>
        </div>
        <strong data-vote-total><%= voteLabel(safeVoteStats.total) %></strong>
      </div>
      <div class="zs-vote-grid">
        <% [
          { choice: 'home', side: 'home', logo: safeMatch.home_logo, label: safeMatch.home_team },
          { choice: 'draw', side: 'draw', logo: '', label: 'Nul' },
          { choice: 'away', side: 'away', logo: safeMatch.away_logo, label: safeMatch.away_team }
        ].forEach((item) => {
          const option = voteOption(item.choice);
          const percent = percentInt(option.percent);
        %>
          <button class="zs-vote-option is-<%= item.side %> <%= safeVoteStats.selected === item.choice ? 'is-selected' : '' %>" type="button" data-vote-choice="<%= item.choice %>" aria-label="Voter <%= item.label %>">
            <i data-vote-fill style="height:<%= percent %>%"></i>
            <small data-vote-count><%= voteLabel(option.count) %></small>
            <% if (item.choice === 'draw') { %>
              <b aria-hidden="true">×</b>
            <% } else if (item.logo) { %>
              <img src="<%= item.logo %>" alt="">
            <% } else { %>
              <b><%= initials(item.label) %></b>
            <% } %>
            <strong data-vote-percent><%= percent %>%</strong>
          </button>
        <% }) %>
      </div>
    </article>

    <article class="zs-stats-card">
      <div class="zs-team-flags">
        <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
        <div>
          <h2>Statistiques offensives clés</h2>
          <p><%= displayedStatsSubtitle %></p>
        </div>
        <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
      </div>
      <div class="zs-stat-list">
        <% if (displayedStatRows.length) { %>
          <% displayedStatRows.forEach((row) => { %>
            <div class="zs-stat-line">
              <strong><%= statDisplayValue(row, 'home') %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= row.homePct %>%"></b>
                  <b class="away" style="width:<%= row.awayPct %>%"></b>
                </i>
              </div>
              <strong><%= statDisplayValue(row, 'away') %></strong>
            </div>
          <% }) %>
        <% } else { %>
          <div class="analysis-v2-empty-note zs-slim-empty">
            <h3>Statistiques indisponibles</h3>
            <p><%= realStatsEmptyCopy %></p>
          </div>
        <% } %>
      </div>
    </article>

    <% if (!isFinishedMatchPage) { %>
      <article class="zs-form-card">
        <div class="zs-card-head">
          <h2>Forme récente</h2>
          <a href="#forme" data-analysis-jump>Détails de la forme</a>
        </div>
        <% [
          { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, cards: homeFormCards },
          { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, cards: awayFormCards }
        ].forEach((team) => { %>
          <div class="zs-form-team">
            <h3>
              <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
              <span><%= team.label %></span>
            </h3>
            <div class="zs-form-strip">
              <% team.cards.forEach((card) => { %>
                <div class="zs-form-mini is-<%= card.result === 'V' ? 'win' : (card.result === 'N' ? 'draw' : 'loss') %>">
                  <strong><%= card.result %></strong>
                  <% if (card.logo) { %><img src="<%= card.logo %>" alt=""><% } else { %><span>?</span><% } %>
                  <small><%= card.score %></small>
                </div>
              <% }) %>
            </div>
          </div>
        <% }) %>
      </article>
    <% } %>

  </section>

  <section class="analysis-v2-card analysis-v2-pronos-panel analysis-v2-tab-panel" id="probabilites" data-analysis-panel="probabilites" hidden>
        <div class="analysis-v2-pronos-head zs-neo-advice-head">
          <p class="eyebrow">Avis IA</p>
          <div class="zs-neo-advice-title">
            <h2>Avis IA de TopStats</h2>
            <span>Le plus safe</span>
          </div>
          <div class="zs-neo-trust-strip" aria-label="Priorité des avis IA">
            <span>Priorité TopStats</span>
            <span>Filtrage risque</span>
            <span>PRO si cote &gt; <%= freeLimit.toFixed(2) %></span>
          </div>
          <p class="zs-neo-safe-note">C’est ici que TopStats garde ses lectures les plus jouables : cotes jusqu’à <%= freeLimit.toFixed(2) %> en gratuit, marchés supérieurs réservés aux membres PRO. Les stats générales plus bas restent informatives.</p>
        </div>

        <% if (allRecommendations.length) { %>
          <div class="analysis-v2-pronos-list <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
            <% allRecommendations.forEach((recommendation, index) => { %>
              <article class="<%= index === 0 ? 'featured' : '' %> <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
                <div>
                  <span><%= index === 0 ? 'Principal' : recommendation.recommendation_type %></span>
                  <h3><%= recommendation.title %></h3>
                  <p>Risque <%= recommendation.risk_level %> · <%= recommendation.confidence %>% confiance</p>
                </div>
                <aside>
                  <% if (recommendation.odds) { %>
                    <strong><%= Number(recommendation.odds).toFixed(2) %></strong>
                    <small><%= recommendation.bookmaker || 'Bookmaker' %></small>
                  <% } else { %>
                    <strong><%= recommendation.confidence %>%</strong>
                    <small>Confiance</small>
                  <% } %>
                </aside>
                <% if (pageAuthLocked) { %>
                  <div class="zs-advice-auth-lock">
                    <span><%= lockedAdviceCopy %></span>
                    <a href="/connexion">Entrar</a>
                  </div>
                <% } %>
              </article>
            <% }) %>
          </div>
        <% } else { %>
          <div class="analysis-v2-empty-note">
            <% if (pageAnalysisLoading) { %>
              <h3>Cargando información...</h3>
              <p>Los mercados y las cuotas se están leyendo. Los pronósticos aparecerán automáticamente cuando el análisis esté listo.</p>
            <% } else if (pageAuthLocked) { %>
              <h3><%= lockedAdviceCopy %></h3>
              <p>Inicia sesión para ver los consejos IA de TopStats en este partido.</p>
            <% } else if (hasOnlyProRecommendations) { %>
              <h3>Avis IA réservés PRO</h3>
              <p>Vérification effectuée : des avis fiables existent, mais ils dépassent la limite gratuite de <%= freeLimit.toFixed(2) %> et restent masqués sur l’accès gratuit.</p>
            <% } else { %>
              <h3>Ningún consejo IA disponible</h3>
              <p><%= recommendationNote || 'Vérification effectuée : TopStats attend une cote exploitable et des signaux cohérents avant de proposer un marché.' %></p>
            <% } %>
          </div>
        <% } %>

        <% if (!pageAuthLocked && pageLocked && hiddenCount > 0) { %>
          <div class="analysis-v2-pro-inline">
            <div>
              <span>PRO</span>
              <strong><%= hiddenCount %> recommandation(s) masquée(s)</strong>
              <p>Cotes supérieures à <%= freeLimit.toFixed(2) %>, marchés plus ambitieux et demandes personnalisées.</p>
            </div>
            <a class="btn btn-primary btn-small" href="/pro">Débloquer</a>
          </div>
        <% } %>

        <div class="zs-neo-scorer-advice">
          <div class="analysis-v2-pronos-head zs-neo-advice-head zs-neo-scorer-head">
            <p class="eyebrow">Buteur</p>
            <div class="zs-neo-advice-title">
              <h2>Avis TopStats Buteur</h2>
              <span>Signal joueur</span>
            </div>
            <p class="zs-neo-safe-note">TopStats affiche un buteur seulement si le marché, la cote, le profil joueur et la projection offensive de son équipe restent alignés.</p>
          </div>

          <% if (scorerAdviceItems.length) { %>
            <div class="analysis-v2-pronos-list <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
              <% scorerAdviceItems.forEach((scorer, index) => { %>
                <article class="<%= index === 0 ? 'featured' : '' %> <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
                  <div>
                    <span><%= index === 0 ? 'Buteur principal' : 'Buteur' %></span>
                    <h3><%= scorer.title || `${scorer.player || 'Joueur'} buteur` %></h3>
                    <p>Risque <%= scorer.risk_level || 'Modéré' %> · <%= scorer.estimated_probability || scorer.confidence %>% confiance</p>
                  </div>
                  <aside>
                    <% const scorerOddValue = Number(scorer.odds || scorer.odd || scorer.price || 0); %>
                    <% if (scorerOddValue > 0) { %>
                      <strong><%= scorerOddValue.toFixed(2) %></strong>
                      <small><%= scorer.bookmaker || 'Bookmaker' %></small>
                    <% } else { %>
                      <strong>-</strong>
                      <small>Cote</small>
                    <% } %>
                  </aside>
                  <% if (pageAuthLocked) { %>
                    <div class="zs-advice-auth-lock">
                      <span><%= lockedAdviceCopy %></span>
                      <a href="/connexion">Entrar</a>
                    </div>
                  <% } %>
                </article>
              <% }) %>
            </div>
          <% } else { %>
            <div class="analysis-v2-empty-note zs-slim-empty">
              <% if (pageAnalysisLoading) { %>
                <h3>Análisis de goleador en curso</h3>
                <p>TopStats vérifie les marchés buteurs et les profils offensifs disponibles.</p>
              <% } else if (pageAuthLocked) { %>
                <h3><%= lockedAdviceCopy %></h3>
                <p>Inicia sesión para ver los consejos de goleadores de TopStats en este partido.</p>
              <% } else if (hasOnlyProScorerRecommendations) { %>
                <h3>Avis buteur réservé PRO</h3>
                <p>Un signal buteur existe, mais sa cote dépasse <%= freeLimit.toFixed(2) %> et reste réservé aux membres PRO.</p>
              <% } else { %>
                <h3>Ningún goleador fiable para este partido</h3>
                <p>Vérification effectuée : aucun joueur ne réunit assez de signaux propres pour être conseillé en buteur.</p>
              <% } %>
            </div>
          <% } %>
        </div>

        <% if (neoGeneralStats.length) { %>
          <div class="zs-ai-info-separator">
            <span>Scores exacts et avis IA TopStats ci-dessus</span>
            <strong>Stats générales informatives</strong>
            <p>La zone suivante aide à comprendre le match, mais ne remplace pas les avis IA de TopStats.</p>
          </div>

          <article class="zs-ai-stats-card">
            <div class="zs-ai-stats-list">
              <% neoGeneralStats.forEach((row) => { %>
                <% const rowLocked = generalStatLocked(row); %>
                <div class="zs-ai-stat-row <%= rowLocked ? 'is-pro-locked' : '' %> <%= pageAuthLocked ? 'is-auth-locked' : '' %>">
                  <div class="zs-ai-stat-main">
                    <strong><%= row.category %></strong>
                    <span class="zs-ai-stat-label">
                      <% if (row.logo) { %><img src="<%= row.logo %>" alt=""><% } %>
                      <em><%= row.label %></em>
                    </span>
                  </div>
                  <div class="zs-ai-stat-values">
                    <div>
                      <small>Proba</small>
                      <b><%= row.probability %>%</b>
                    </div>
                    <div>
                      <small>Cote</small>
                      <b><%= oddsFr(row.odd) %></b>
                    </div>
                  </div>
                  <% if (rowLocked) { %>
                    <div class="zs-ai-stat-lock" aria-label="<%= pageAuthLocked ? lockedAdviceCopy : 'Statistique réservée aux membres PRO' %>">
                      <span><%= pageAuthLocked ? lockedAdviceCopy : `Cote supérieur à ${freeLimit.toFixed(2)} réservé aux membres PRO` %></span>
                    </div>
                  <% } %>
                </div>
              <% }) %>
            </div>
          </article>
        <% } %>

        <article class="zs-score-prob-card zs-score-matrix-bottom-card <%= pageLocked ? 'is-locked' : '' %>">
          <div class="zs-score-prob-head">
            <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
            <div>
              <h2>Probabilité du score</h2>
              <p>Modélisation basée sur les performances des équipes sur les 10 derniers matchs</p>
            </div>
            <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
          </div>

          <div class="zs-score-matrix <%= pageLocked ? 'is-locked' : '' %>" aria-label="Matrice de scores exacts">
            <div class="zs-score-matrix-scroll">
              <div class="zs-score-matrix-grid" style="--matrix-size: <%= scoreMatrixMaxGoal + 2 %>;">
                <i></i>
                <% scoreMatrixLabels.forEach((awayGoal) => { %>
                  <b><%= awayGoal %></b>
                <% }) %>
                <% scoreMatrixRows.forEach((row) => { %>
                  <b><%= row.home %></b>
                  <% row.cells.forEach((cell) => { %>
                    <span class="is-level-<%= cell.intensity %> <%= cell.featured ? 'is-hot' : '' %>">
                      <strong><%= scoreMatrixPercent(cell.probability) %><small>%</small></strong>
                    </span>
                  <% }) %>
                <% }) %>
              </div>
            </div>
            <div class="zs-score-matrix-axes">
              <span><i>↑</i><small>0<sup>5</sup></small> Buts <% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><b><%= initials(safeMatch.home_team) %></b><% } %></span>
              <span><small>0<sup>5</sup></small><i>→</i> Buts <% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><b><%= initials(safeMatch.away_team) %></b><% } %></span>
            </div>
            <% if (pageLocked) { %>
              <div class="zs-score-matrix-lock" aria-hidden="true">
                <span>🔒</span>
                <strong><%= pageAuthLocked ? lockedAdviceCopy : 'Réservé aux Membres PRO' %></strong>
              </div>
            <% } %>
          </div>

          <div class="analysis-v2-scenario-grid zs-exact-score-row zs-score-prob-row <%= pageLocked ? 'is-pro-locked' : '' %>" aria-label="Scores probables">
            <% exactScoreCards.forEach((scenario, index) => { %>
              <article class="zs-exact-score-card <%= index === 0 ? 'featured is-favorite' : '' %> <%= pageLocked ? 'is-card-locked' : '' %>">
                <div class="zs-exact-score-content">
                  <small><%= exactScoreTitle(index) %></small>
                  <div class="zs-score-fixture">
                    <strong><%= exactScoreValue(scenario, index) %></strong>
                  </div>
                  <div class="zs-score-reading">
                    <span>Probabilité</span>
                    <em><%= oneDecimalFr(exactScoreProbability(scenario, index)) %>%</em>
                  </div>
                </div>
                <% if (pageLocked) { %>
                  <div class="zs-score-card-lock" aria-hidden="true">
                    <span>🔒</span>
                    <strong><%= pageAuthLocked ? lockedAdviceCopy : 'Réservé aux Membres PRO' %></strong>
                  </div>
                <% } %>
              </article>
            <% }) %>
          </div>

          <% if (pageLocked) { %>
            <div class="zs-score-pro-note">
              <span aria-hidden="true">🔒</span>
              <p><%= pageAuthLocked ? 'Inicia sesión para ver los marcadores exactos y probabilidades generadas por TopStats.' : 'Los marcadores exactos están reservados a miembros PRO. La vista sigue visible, pero los valores están ocultos.' %></p>
              <a href="<%= lockedAdviceHref %>"><%= lockedAdviceAction %></a>
            </div>
          <% } %>
        </article>
  </section>

  <% if (pageAnalysisLocked && !isFinishedMatchPage) { %>
    <section class="analysis-v2-card analysis-v2-pro-inline analysis-v2-pro-gate analysis-v2-tab-panel" data-analysis-panel="resume">
      <div>
        <span><%= pageAuthLocked ? 'Iniciar sesión' : 'PRO' %></span>
        <strong><%= pageAuthLocked ? lockedAdviceCopy : 'Análisis completo prepartido reservado para miembros PRO' %></strong>
        <p><%= pageAuthLocked ? 'Inicia sesión para ver el análisis IA completo de TopStats en este partido. Las estadísticas, alineaciones y cuotas siguen disponibles.' : `El análisis detallado, los escenarios de marcador, los goleadores y los mercados por encima de ${freeLimit.toFixed(2)} están reservados a miembros PRO. Las estadísticas, alineaciones y cuotas siguen disponibles.` %></p>
      </div>
      <a class="btn btn-primary" href="<%= lockedAdviceHref %>"><%= lockedAdviceAction %></a>
    </section>
  <% } %>

  <section class="analysis-v2-card analysis-v2-mobile-extra analysis-v2-tab-panel" id="stats" data-analysis-panel="stats" hidden>
    <div class="analysis-v2-section-title">
      <div>
        <p class="eyebrow">Stats</p>
        <h2>Indicateurs clés</h2>
        <p>Forme, rendement et tendances disponibles avant le match.</p>
      </div>
    </div>
    <nav class="zs-stats-subtabs" aria-label="Sous-sections statistiques" data-zs-stats-tabs>
      <button type="button" class="is-active" data-zs-stats-filter="top">Top des stats</button>
      <button type="button" data-zs-stats-filter="selections">Sélections (29)</button>
      <button type="button" data-zs-stats-filter="outils">Outils paris</button>
      <button type="button" data-zs-stats-filter="buts">Buts</button>
      <button type="button" data-zs-stats-filter="mi-temps">Buts par mi-temps</button>
      <button type="button" data-zs-stats-filter="tirs">Tirs par équipe</button>
      <button type="button" data-zs-stats-filter="buteurs">Buteurs</button>
      <button type="button" data-zs-stats-filter="tirs-joueur">Tirs par joueur</button>
      <button type="button" data-zs-stats-filter="scenarios">Scénarios</button>
      <button type="button" data-zs-stats-filter="matrix">Matrice de scores</button>
    </nav>
    <% if (showPreMatchStatTools) { %>
      <article class="zs-stats-card zs-result-prob-card zs-stats-sub-card" data-zs-stats-groups="top selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Probabilité du résultat</h2>
            <p>Estimée par le modèle statistique TopStats</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-result-prob-grid">
          <% resultProbabilityRows.forEach((item) => { %>
            <div class="zs-result-prob-pill is-<%= item.type %>">
              <% if (item.logo) { %><img src="<%= item.logo %>" alt=""><% } else { %><span><%= item.type === 'draw' ? 'X' : initials(item.label) %></span><% } %>
              <strong><%= item.type === 'draw' ? 'X' : (item.type === 'home' ? '1' : '2') %></strong>
              <b><%= clampPercent(item.value) %>%</b>
            </div>
          <% }) %>
        </div>
      </article>
    <% } %>
    <article class="zs-stats-card zs-stats-card-tab zs-stats-sub-card" data-zs-stats-groups="top tirs selections">
      <div class="zs-team-flags">
        <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
        <div>
          <h2>Statistiques offensives clés</h2>
          <p><%= displayedStatsSubtitle %></p>
        </div>
        <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
      </div>
      <div class="zs-stat-list">
        <% if (displayedStatRows.length) { %>
          <% displayedStatRows.forEach((row) => { %>
            <div class="zs-stat-line">
              <strong><%= statDisplayValue(row, 'home') %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= row.homePct %>%"></b>
                  <b class="away" style="width:<%= row.awayPct %>%"></b>
                </i>
              </div>
              <strong><%= statDisplayValue(row, 'away') %></strong>
            </div>
          <% }) %>
        <% } else { %>
          <div class="analysis-v2-empty-note zs-slim-empty">
            <h3>Statistiques indisponibles</h3>
            <p><%= realStatsEmptyCopy %></p>
          </div>
        <% } %>
      </div>
    </article>

    <% if (showPreMatchStatTools) { %>
      <article class="zs-stats-card zs-stats-card-tab zs-stats-sub-card" data-zs-stats-groups="top tirs">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Situations décisives</h2>
            <p>Moyennes par match sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-stat-list">
          <% decisiveSituationRows.forEach((row) => { %>
            <div class="zs-stat-line">
              <strong><%= statDisplayValue(row, 'home') %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= row.homePct %>%"></b>
                  <b class="away" style="width:<%= row.awayPct %>%"></b>
                </i>
              </div>
              <strong><%= statDisplayValue(row, 'away') %></strong>
            </div>
          <% }) %>
        </div>
      </article>

      <article class="zs-stats-card zs-stats-card-tab zs-stats-sub-card" data-zs-stats-groups="top scenarios">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Temps forts</h2>
            <p>Sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-stat-list">
          <% highlightRows.forEach((row) => { %>
            <div class="zs-stat-line">
              <strong><%= statDisplayValue(row, 'home') %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= row.homePct %>%"></b>
                  <b class="away" style="width:<%= row.awayPct %>%"></b>
                </i>
              </div>
              <strong><%= statDisplayValue(row, 'away') %></strong>
            </div>
          <% }) %>
        </div>
      </article>

      <article class="zs-stats-card zs-stats-card-tab zs-stats-sub-card" data-zs-stats-groups="top outils">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Gestion du match</h2>
            <p>Moyennes par match sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-stat-list">
          <% matchManagementRows.forEach((row) => { %>
            <div class="zs-stat-line">
              <strong><%= statDisplayValue(row, 'home') %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= row.homePct %>%"></b>
                  <b class="away" style="width:<%= row.awayPct %>%"></b>
                </i>
              </div>
              <strong><%= statDisplayValue(row, 'away') %></strong>
            </div>
          <% }) %>
        </div>
      </article>
    <% } %>

    <% if (showPreMatchStatTools) { %>
      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="buts selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>But pour les 2 équipes</h2>
            <p>Cas où les deux équipes marquent sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-prestat-duo">
          <% [
            { side: 'home', label: safeMatch.home_team || 'Domicile', trend: homeRecentTrend },
            { side: 'away', label: safeMatch.away_team || 'Extérieur', trend: awayRecentTrend }
          ].forEach((item) => { %>
            <div class="zs-prestat-ring is-<%= item.side %>">
              <i style="--value:<%= trendPct(item.trend.btts, item.trend.count) %>%"><span><%= item.trend.btts || 0 %>/<%= item.trend.count || 0 %></span></i>
              <strong><%= item.trend.btts || 0 %> fois</strong>
              <small><%= item.label %></small>
            </div>
          <% }) %>
        </div>
      </article>

      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="mi-temps selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Mi-temps avec le plus de buts</h2>
            <p>Sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-prestat-duo zs-prestat-halves">
          <% [
            { side: 'home', label: safeMatch.home_team || 'Domicile', trend: homeRecentTrend },
            { side: 'away', label: safeMatch.away_team || 'Extérieur', trend: awayRecentTrend }
          ].forEach((item) => { %>
            <div class="zs-prestat-half is-<%= item.side %>">
              <span><%= item.trend.halfAvailable ? item.trend.bestHalf.label : '-' %></span>
              <strong><%= item.trend.halfAvailable ? `${item.trend.bestHalf.count}/${item.trend.halfTotal}` : 'Indispo' %></strong>
              <small><%= item.label %></small>
            </div>
          <% }) %>
        </div>
      </article>

      <% if (hasHalfScoreTrend) { %>
        <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="mi-temps selections">
          <div class="zs-team-flags">
            <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
            <div>
              <h2>Score à la mi-temps le plus fréquent</h2>
              <p>Sur les 5 derniers matchs</p>
            </div>
            <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
          </div>
          <div class="zs-prestat-duo zs-prestat-halves">
            <% [
              { side: 'home', label: safeMatch.home_team || 'Domicile', trend: homeRecentTrend },
              { side: 'away', label: safeMatch.away_team || 'Extérieur', trend: awayRecentTrend }
            ].forEach((item) => { %>
              <div class="zs-prestat-half is-<%= item.side %>">
                <span><%= item.trend.bestHalfScore ? item.trend.bestHalfScore.label : '-' %></span>
                <strong><%= item.trend.bestHalfScore ? `${item.trend.bestHalfScore.count}/${item.trend.halfScoreTotal}` : 'Indispo' %></strong>
                <small><%= item.label %></small>
              </div>
            <% }) %>
          </div>
        </article>
      <% } %>

      <% if (hasCardTrend) { %>
        <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="outils selections">
          <div class="zs-team-flags">
            <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
            <div>
              <h2>Nombre de cartons par équipe</h2>
              <p>Moyenne sur les 5 derniers matchs</p>
            </div>
            <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
          </div>
          <div class="zs-prestat-duo zs-prestat-halves">
            <% [
              { side: 'home', label: safeMatch.home_team || 'Domicile', trend: homeRecentTrend },
              { side: 'away', label: safeMatch.away_team || 'Extérieur', trend: awayRecentTrend }
            ].forEach((item) => { %>
              <div class="zs-prestat-half is-<%= item.side %>">
                <span><%= item.trend.cardAvailable ? numberFr(item.trend.avgCards) : '-' %></span>
                <strong><%= item.trend.cardAvailable ? `${item.trend.cardTotal} carton${item.trend.cardTotal > 1 ? 's' : ''}` : 'Indispo' %></strong>
                <small><%= item.trend.cardAvailable ? `${item.trend.cardMatches} match${item.trend.cardMatches > 1 ? 's' : ''}` : item.label %></small>
              </div>
            <% }) %>
          </div>
        </article>
      <% } %>

      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="buts outils selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Total de buts marqués dans le match</h2>
            <p>Sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-prestat-thresholds">
          <% homeRecentTrend.matchGoals.forEach((homeItem, index) => {
            const awayItem = awayRecentTrend.matchGoals[index] || { count: 0, total: awayRecentTrend.count || 5 };
          %>
            <div class="zs-prestat-threshold">
              <strong><%= homeItem.count %>/<%= homeItem.total || 0 %></strong>
              <div>
                <span><%= homeItem.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= thresholdWidth(homeItem) %>%"></b>
                  <b class="away" style="width:<%= thresholdWidth(awayItem) %>%"></b>
                </i>
              </div>
              <strong><%= awayItem.count %>/<%= awayItem.total || 0 %></strong>
            </div>
          <% }) %>
        </div>
      </article>

      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="buts selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Total de buts marqués par équipe</h2>
            <p>Sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-prestat-thresholds">
          <% homeRecentTrend.teamGoals.forEach((homeItem, index) => {
            const awayItem = awayRecentTrend.teamGoals[index] || { count: 0, total: awayRecentTrend.count || 5 };
          %>
            <div class="zs-prestat-threshold">
              <strong><%= homeItem.count %>/<%= homeItem.total || 0 %></strong>
              <div>
                <span><%= homeItem.label %></span>
                <i aria-hidden="true">
                  <b class="home" style="width:<%= thresholdWidth(homeItem) %>%"></b>
                  <b class="away" style="width:<%= thresholdWidth(awayItem) %>%"></b>
                </i>
              </div>
              <strong><%= awayItem.count %>/<%= awayItem.total || 0 %></strong>
            </div>
          <% }) %>
        </div>
      </article>

      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="buteurs selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Meilleur buteur par équipe</h2>
            <p>Donnée joueur disponible avant match</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-prestat-duo zs-prestat-scorers">
          <% [
            { side: 'home', label: safeMatch.home_team || 'Domicile', player: homeTopScorer },
            { side: 'away', label: safeMatch.away_team || 'Extérieur', player: awayTopScorer }
          ].forEach((item) => { %>
            <div class="zs-prestat-scorer is-<%= item.side %>">
              <% if (item.player && item.player.photo) { %>
                <img src="<%= item.player.photo %>" alt="">
              <% } else { %>
                <span><%= item.player ? playerInitials(item.player.name) : '—' %></span>
              <% } %>
              <div>
                <strong><%= item.player ? item.player.name : 'Donnée indisponible' %></strong>
                <small><%= item.player ? `${item.player.goals} but${item.player.goals > 1 ? 's' : ''}` : item.label %></small>
              </div>
            </div>
          <% }) %>
        </div>
      </article>

      <% if (hasPlayerShotRows) { %>
        <article class="zs-stats-card zs-prestat-card zs-player-shots-card zs-stats-sub-card" data-zs-stats-groups="tirs-joueur selections">
          <div class="zs-team-flags">
            <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
            <div>
              <h2>Total de tirs par joueur</h2>
              <p>Moyennes estimées par match sur les 5 derniers matchs</p>
            </div>
            <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
          </div>
          <div class="zs-player-shots-market">Tirs par match</div>
          <div class="zs-player-shots-teams">
            <% [
              { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, rows: homePlayerShotRows },
              { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, rows: awayPlayerShotRows }
            ].forEach((team) => { %>
              <div class="zs-player-shot-team is-<%= team.side %>">
                <h3>
                  <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
                  <span><%= team.label %></span>
                </h3>
                <div class="zs-player-shot-list">
                  <% if (team.rows.length) { %>
                    <% team.rows.slice(0, 3).forEach((player) => { %>
                      <div class="zs-player-shot-row">
                        <span>
                          <% if (player.photo) { %><img src="<%= player.photo %>" alt=""><% } else { %><i><%= playerInitials(player.name) %></i><% } %>
                          <b><%= player.name %></b>
                        </span>
                        <strong><%= oneDecimalFr(player.shots) %></strong>
                      </div>
                    <% }) %>
                    <% if (team.rows.length > 3) { %>
                      <details class="zs-player-shot-more-details">
                        <summary>Voir plus</summary>
                        <div class="zs-player-shot-list zs-player-shot-list-extra">
                          <% team.rows.slice(3).forEach((player) => { %>
                            <div class="zs-player-shot-row">
                              <span>
                                <% if (player.photo) { %><img src="<%= player.photo %>" alt=""><% } else { %><i><%= playerInitials(player.name) %></i><% } %>
                                <b><%= player.name %></b>
                              </span>
                              <strong><%= oneDecimalFr(player.shots) %></strong>
                            </div>
                          <% }) %>
                        </div>
                      </details>
                    <% } %>
                  <% } else { %>
                    <p class="zs-player-shot-empty">Joueurs indisponibles</p>
                  <% } %>
                </div>
              </div>
            <% }) %>
          </div>
        </article>
      <% } %>

      <article class="zs-stats-card zs-prestat-card zs-scenario-situation-card zs-stats-sub-card" data-zs-stats-groups="scenarios selections">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Résultats selon la situation</h2>
            <p>Sur les 5 derniers matchs</p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-scenario-situation-list">
          <% if (scenarioRows.length) { %>
            <% scenarioRows.forEach((row) => { %>
              <div class="zs-scenario-situation-row">
                <strong><%= scenarioFraction(row.home) %></strong>
                <span><%= row.label %></span>
                <strong><%= scenarioFraction(row.away) %></strong>
              </div>
            <% }) %>
          <% } else { %>
            <div class="analysis-v2-empty-note zs-slim-empty">
              <h3>Scénarios indisponibles</h3>
              <p>Les derniers matchs ne contiennent pas assez de données de mi-temps fiables.</p>
            </div>
          <% } %>
        </div>
      </article>

      <article class="zs-stats-card zs-prestat-card zs-stats-sub-card" data-zs-stats-groups="matrix outils">
        <div class="zs-team-flags">
          <span><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
          <div>
            <h2>Matrice de scores</h2>
            <p>Vertical : <%= safeMatch.home_team || 'Domicile' %> · Horizontal : <%= safeMatch.away_team || 'Extérieur' %></p>
          </div>
          <span><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
        </div>
        <div class="zs-score-matrix zs-score-matrix-stats <%= pageLocked ? 'is-locked' : '' %>" aria-label="Matrice de scores exacts">
          <div class="zs-score-matrix-scroll">
            <div class="zs-score-matrix-grid" style="--matrix-size: <%= scoreMatrixMaxGoal + 2 %>;">
              <span class="zs-score-matrix-corner"></span>
              <% scoreMatrixLabels.forEach((awayGoals) => { %>
                <span class="zs-score-matrix-axis"><%= awayGoals %></span>
              <% }) %>
              <% scoreMatrixRows.forEach((row) => { %>
                <span class="zs-score-matrix-axis"><%= row.home %></span>
                <% row.cells.forEach((cell) => { %>
                  <span class="zs-score-matrix-cell is-level-<%= cell.intensity %> <%= cell.featured ? 'is-featured' : '' %>">
                    <%= scoreMatrixPercent(cell.probability) %><small>%</small>
                  </span>
                <% }) %>
              <% }) %>
            </div>
          </div>
          <div class="zs-score-matrix-axes">
            <span>Vertical : <% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } %><%= safeMatch.home_team || 'Domicile' %></span>
            <span>Horizontal : <% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } %><%= safeMatch.away_team || 'Extérieur' %></span>
          </div>
        </div>
        <div class="analysis-v2-scenario-grid zs-exact-score-row zs-stats-score-row <%= scoreScenarioData && scoreScenarioData.low_confidence ? 'is-low-confidence' : '' %> <%= pageLocked ? 'is-pro-locked' : '' %>">
          <% exactScoreCards.forEach((scenario, index) => { %>
            <article class="zs-exact-score-card <%= index === 0 ? 'featured is-favorite' : '' %> <%= pageLocked ? 'is-card-locked' : '' %>">
              <div class="zs-exact-score-content">
                <small><%= exactScoreTitle(index) %></small>
                <div class="zs-score-fixture">
                  <span class="zs-score-team"><% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %></span>
                  <strong><%= exactScoreValue(scenario, index) %></strong>
                  <span class="zs-score-team"><% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %></span>
                </div>
                <div class="zs-score-reading">
                  <span><%= oneDecimalFr(exactScoreProbability(scenario, index)) %>%</span>
                  <em>Probabilité</em>
                </div>
              </div>
            </article>
          <% }) %>
        </div>
      </article>
    <% } %>

    <div class="analysis-v2-empty-note zs-slim-empty zs-stats-sub-empty" data-zs-stats-empty hidden>
      <h3>No hay estadísticas disponibles</h3>
      <p>Cette sous-section s’affichera dès que TopStats récupère assez de données fiables.</p>
    </div>

    <% if (!shouldUseRealStats) { %>
      <article class="zs-form-card zs-form-card-tab">
        <div class="zs-card-head">
          <h2>Forme récente</h2>
          <a href="#forme" data-analysis-jump>Détails de la forme</a>
        </div>
        <% [
          { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, cards: homeFormCards },
          { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, cards: awayFormCards }
        ].forEach((team) => { %>
          <div class="zs-form-team">
            <h3>
              <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
              <span><%= team.label %></span>
            </h3>
            <div class="zs-form-strip">
              <% team.cards.forEach((card) => { %>
                <div class="zs-form-mini is-<%= card.result === 'V' ? 'win' : (card.result === 'N' ? 'draw' : 'loss') %>">
                  <strong><%= card.result %></strong>
                  <% if (card.logo) { %><img src="<%= card.logo %>" alt=""><% } else { %><span>?</span><% } %>
                  <small><%= card.score %></small>
                </div>
              <% }) %>
            </div>
          </div>
        <% }) %>
      </article>
    <% } %>

    <% if (!shouldUseRealStats && hasRecentStats) { %>
      <div class="analysis-v2-stats-panel">
        <div class="analysis-v2-stats-title">
          <span class="analysis-v2-mini-flag">
            <% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %>
          </span>
          <div>
            <h3>Indicateurs clés</h3>
            <p>Forme, rendement et tendances disponibles</p>
          </div>
          <span class="analysis-v2-mini-flag">
            <% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %>
          </span>
        </div>

        <div class="analysis-v2-form-cards">
          <article>
            <strong><%= safeMatch.home_team || 'Domicile' %></strong>
            <p><span class="win"><%= formWins(recentHome) %>V</span><span><%= formDraws(recentHome) %>N</span><span class="loss"><%= formLosses(recentHome) %>D</span></p>
            <small><%= recentCount(recentHome) %> derniers matchs</small>
          </article>
          <article>
            <strong><%= safeMatch.away_team || 'Extérieur' %></strong>
            <p><span class="win"><%= formWins(recentAway) %>V</span><span><%= formDraws(recentAway) %>N</span><span class="loss"><%= formLosses(recentAway) %>D</span></p>
            <small><%= recentCount(recentAway) %> derniers matchs</small>
          </article>
        </div>

        <div class="analysis-v2-stat-bars">
          <% statMetricRows.forEach((row) => { %>
            <div class="analysis-v2-stat-row">
              <strong><%= formatMetric(row.home, row.suffix) %></strong>
              <div>
                <span><%= row.label %></span>
                <i aria-hidden="true"><b class="home" style="width:<%= row.homePct %>%"></b><b class="away" style="width:<%= row.awayPct %>%"></b></i>
              </div>
              <strong><%= formatMetric(row.away, row.suffix) %></strong>
            </div>
          <% }) %>
        </div>
      </div>
    <% } else if (!shouldUseRealStats) { %>
      <div class="analysis-v2-reading-grid">
        <div>
          <span>Forme récente</span>
          <strong><%= displayAnalysis.team_form || 'Données en cours de lecture' %></strong>
        </div>
        <div>
          <span>Signaux clés</span>
          <strong><%= displayAnalysis.key_stats || 'Données en cours de lecture' %></strong>
        </div>
        <div>
          <span>Points forts</span>
          <strong><%= displayAnalysis.strengths || 'Données en cours de lecture' %></strong>
        </div>
        <div>
          <span>Risques</span>
          <strong><%= displayAnalysis.risks || 'Données en cours de lecture' %></strong>
        </div>
      </div>
    <% } %>
  </section>

  <section class="analysis-v2-card analysis-v2-mobile-extra analysis-v2-tab-panel" id="compos" data-analysis-panel="compos" hidden>
    <div class="analysis-v2-section-title">
      <div>
        <p class="eyebrow">Compos</p>
        <h2>Compositions</h2>
        <p>Les compositions probables ou officielles s’affichent dès qu’elles sont disponibles.</p>
      </div>
    </div>
    <% if (hasLineupDisplay) { %>
      <div class="analysis-v2-lineup-wrap">
        <div class="analysis-v2-lineup-meta">
          <div>
            <strong><%= safeMatch.home_team || 'Domicile' %><%= homeLineup && homeLineup.formation ? ` ${homeLineup.formation}` : '' %></strong>
            <span><%= homeLineup && homeLineup.status_label ? homeLineup.status_label : lineupStatusCopy %></span>
          </div>
          <div>
            <strong><%= awayLineup && awayLineup.formation ? `${awayLineup.formation} ` : '' %><%= safeMatch.away_team || 'Extérieur' %></strong>
            <span><%= awayLineup && awayLineup.status_label ? awayLineup.status_label : lineupStatusCopy %></span>
          </div>
        </div>

        <div class="zs-lineup-boards" aria-label="Graphique des compositions">
          <% [
            { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, lineup: homeLineup },
            { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, lineup: awayLineup }
          ].forEach((team) => {
            const starters = sortedLineupPlayers(team.lineup);
          %>
            <section class="zs-lineup-board is-<%= team.side %>">
              <header>
                <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
                <div>
                  <strong><%= team.label %></strong>
                  <span><%= team.lineup?.formation || 'Formation' %></span>
                </div>
              </header>
              <% if (starters.length) { %>
                <div class="zs-lineup-pitch-mini">
                  <i aria-hidden="true"></i>
                  <% starters.forEach((player, index) => { %>
                    <div class="analysis-v2-lineup-player is-<%= team.side %>" style="<%= lineupMiniPositionStyle(player, index, team.lineup) %>">
                      <% if (player.photo) { %>
                        <img src="<%= player.photo %>" alt="">
                      <% } else { %>
                        <span class="analysis-v2-player-avatar"><%= player.number || playerInitials(player.name) %></span>
                      <% } %>
                      <b><%= playerShortName(player.name) %></b>
                    </div>
                  <% }) %>
                </div>
              <% } else { %>
                <p class="zs-lineup-empty">Titulaires non publiés.</p>
              <% } %>
            </section>
          <% }) %>
        </div>

        <div class="zs-lineup-details">
          <% [
            { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, lineup: homeLineup },
            { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, lineup: awayLineup }
          ].forEach((team) => { %>
            <section class="zs-lineup-team">
              <header>
                <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
                <div>
                  <strong><%= team.label %></strong>
                  <span><%= team.lineup?.formation ? `Formation ${team.lineup.formation}` : lineupStatusCopy %></span>
                </div>
              </header>
              <% if (team.lineup?.coach?.name) { %>
                <p class="zs-lineup-coach">Coach : <strong><%= team.lineup.coach.name %></strong></p>
              <% } %>
              <% if (Array.isArray(team.lineup?.substitutes) && team.lineup.substitutes.length) { %>
                <div class="zs-lineup-bench">
                  <span>Remplaçants</span>
                  <% team.lineup.substitutes.slice(0, 8).forEach((player) => { %>
                    <small><%= player.number ? `${player.number}. ` : '' %><%= playerShortName(player.name) %></small>
                  <% }) %>
                </div>
              <% } else { %>
                <p class="zs-lineup-empty">Banc non publié.</p>
              <% } %>
            </section>
          <% }) %>
        </div>
      </div>
    <% } else { %>
      <div class="zs-lineup-missing">
        <% [
          { label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo },
          { label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo }
        ].forEach((team) => { %>
          <article>
            <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
            <strong><%= team.label %></strong>
            <span>Composition non publiée</span>
          </article>
        <% }) %>
        <p>TopStats affiche les titulaires, formations, coachs et remplaçants dès que les données fiables sont disponibles.</p>
      </div>
    <% } %>
  </section>

  <section class="analysis-v2-card analysis-v2-mobile-extra analysis-v2-tab-panel" id="forme" data-analysis-panel="forme" hidden>
    <article class="zs-odds-card zs-odds-card-compact">
      <div class="zs-card-head">
        <h2>Les cotes du match</h2>
        <span><%= matchOdds && matchOdds.bookmaker ? matchOdds.bookmaker : 'Cotes' %></span>
      </div>
      <div class="zs-odds-grid">
        <div><span>1</span><strong><%= matchOdds && matchOdds.home ? Number(matchOdds.home).toFixed(2) : '-' %></strong></div>
        <div><span>X</span><strong><%= matchOdds && matchOdds.draw ? Number(matchOdds.draw).toFixed(2) : '-' %></strong></div>
        <div><span>2</span><strong><%= matchOdds && matchOdds.away ? Number(matchOdds.away).toFixed(2) : '-' %></strong></div>
      </div>
    </article>

    <article class="zs-match-list-card" data-form-tabs>
      <div class="zs-h2h-toggle" role="tablist" aria-label="Filtrer les derniers matchs">
        <button class="<%= defaultFormPanel === 'home' ? 'is-active' : '' %>" type="button" data-form-tab="home" aria-selected="<%= defaultFormPanel === 'home' ? 'true' : 'false' %>">
          <% if (safeMatch.home_logo) { %><img src="<%= safeMatch.home_logo %>" alt=""><% } else { %><%= initials(safeMatch.home_team) %><% } %>
        </button>
        <button class="<%= defaultFormPanel === 'h2h' ? 'is-active' : '' %>" type="button" data-form-tab="h2h" aria-selected="<%= defaultFormPanel === 'h2h' ? 'true' : 'false' %>">H2H</button>
        <button class="<%= defaultFormPanel === 'away' ? 'is-active' : '' %>" type="button" data-form-tab="away" aria-selected="<%= defaultFormPanel === 'away' ? 'true' : 'false' %>">
          <% if (safeMatch.away_logo) { %><img src="<%= safeMatch.away_logo %>" alt=""><% } else { %><%= initials(safeMatch.away_team) %><% } %>
        </button>
      </div>

      <% historyPanels.forEach((panel) => { %>
        <div class="zs-history-panel <%= panel.key === defaultFormPanel ? 'is-active' : '' %>" data-form-panel="<%= panel.key %>" <%= panel.key === defaultFormPanel ? '' : 'hidden' %>>
          <div class="zs-card-head zs-history-head">
            <div>
              <h2><%= panel.title %></h2>
              <p><%= panel.subtitle %></p>
            </div>
          </div>

          <% if (panel.rows.length) { %>
            <div class="zs-history-list">
              <% panel.rows.forEach((fixture) => {
                const homeTeam = fixture?.teams?.home || {};
                const awayTeam = fixture?.teams?.away || {};
                const homeGoals = fixture?.goals?.home ?? fixture?.score_home ?? '-';
                const awayGoals = fixture?.goals?.away ?? fixture?.score_away ?? '-';
              %>
                <div class="zs-history-item">
                  <div class="zs-history-league">
                    <% if (fixtureLogo(fixture)) { %><img src="<%= fixtureLogo(fixture) %>" alt=""><% } %>
                    <strong><%= fixtureCompetition(fixture) %></strong>
                  </div>
                  <div class="zs-history-match">
                    <time><%= fixtureDate(fixture) %><small><%= fixtureStatus(fixture) %></small></time>
                    <div>
                      <p>
                        <% if (homeTeam.logo) { %><img src="<%= homeTeam.logo %>" alt=""><% } %>
                        <span><%= homeTeam.name || fixture.home_team || 'Domicile' %></span>
                        <strong><%= homeGoals %></strong>
                      </p>
                      <p>
                        <% if (awayTeam.logo) { %><img src="<%= awayTeam.logo %>" alt=""><% } %>
                        <span><%= awayTeam.name || fixture.away_team || 'Extérieur' %></span>
                        <strong><%= awayGoals %></strong>
                      </p>
                    </div>
                  </div>
                </div>
              <% }) %>
            </div>
          <% } else { %>
            <div class="analysis-v2-empty-note zs-slim-empty">
              <h3>Ningún partido disponible</h3>
              <p>Les derniers matchs s’affichent dès que la donnée est disponible.</p>
            </div>
          <% } %>
        </div>
      <% }) %>
    </article>

    <article class="zs-form-card zs-form-card-tab">
      <div class="zs-card-head">
        <h2>Forme récente</h2>
        <span>5 derniers matchs</span>
      </div>
      <% [
        { side: 'home', label: safeMatch.home_team || 'Domicile', logo: safeMatch.home_logo, cards: homeFormCards },
        { side: 'away', label: safeMatch.away_team || 'Extérieur', logo: safeMatch.away_logo, cards: awayFormCards }
      ].forEach((team) => { %>
        <div class="zs-form-team">
          <h3>
            <% if (team.logo) { %><img src="<%= team.logo %>" alt=""><% } %>
            <span><%= team.label %></span>
          </h3>
          <div class="zs-form-strip">
            <% team.cards.forEach((card) => { %>
              <div class="zs-form-mini is-<%= card.result === 'V' ? 'win' : (card.result === 'N' ? 'draw' : 'loss') %>">
                <strong><%= card.result %></strong>
                <% if (card.logo) { %><img src="<%= card.logo %>" alt=""><% } else { %><span>?</span><% } %>
                <small><%= card.score %></small>
              </div>
            <% }) %>
          </div>
        </div>
      <% }) %>
    </article>
  </section>

  <section class="analysis-v2-card analysis-v2-mobile-extra analysis-v2-tab-panel" id="classement" data-analysis-panel="classement" hidden>
    <article class="zs-standing-card">
      <div class="zs-card-head zs-standing-head">
        <div>
          <h2>Classement</h2>
          <p><%= safeMatch.competition_name || 'Compétition' %></p>
        </div>
      </div>

      <% if (standingGroups.length) { %>
        <% standingGroups.forEach((group) => { %>
          <section class="zs-standing-group">
            <h3><%= group.group %></h3>
            <div class="zs-standing-table">
              <div class="zs-standing-row zs-standing-row-head">
                <span>#</span>
                <span>Équipe</span>
                <span>J</span>
                <span>G</span>
                <span>N</span>
                <span>P</span>
                <span>Diff</span>
                <span>Pts</span>
              </div>
              <% group.rows.forEach((row) => { %>
                <div class="zs-standing-row <%= row.is_match_team ? 'is-highlighted' : '' %>">
                  <span><%= row.rank || '-' %></span>
                  <span>
                    <% if (row.team.logo) { %><img src="<%= row.team.logo %>" alt=""><% } %>
                    <strong><%= row.team.name || 'Équipe' %></strong>
                  </span>
                  <span><%= row.played ?? '-' %></span>
                  <span><%= row.win ?? '-' %></span>
                  <span><%= row.draw ?? '-' %></span>
                  <span><%= row.lose ?? '-' %></span>
                  <span><%= row.goals_diff ?? '-' %></span>
                  <span><%= row.points ?? '-' %></span>
                </div>
              <% }) %>
            </div>
          </section>
        <% }) %>
      <% } else { %>
        <div class="analysis-v2-empty-note zs-slim-empty">
          <h3>Classement indisponible</h3>
          <p>Le classement s’affiche dès que la compétition publie une table exploitable.</p>
        </div>
      <% } %>
    </article>
  </section>

  <section class="analysis-v2-card analysis-v2-mobile-extra analysis-v2-tab-panel" id="cotes" data-analysis-panel="cotes" hidden>
    <div class="analysis-v2-section-title">
      <div>
        <p class="eyebrow">Cotes</p>
        <h2>Cotes du match</h2>
        <p>Les cotes affichées peuvent évoluer avant le coup d’envoi.</p>
      </div>
    </div>
    <% if (matchOdds) { %>
      <div class="analysis-v2-pronos-list analysis-v2-odds-table">
        <article>
          <div>
            <span>1X2</span>
            <h3><%= safeMatch.home_team || 'Domicile' %> gagne</h3>
          </div>
          <aside>
            <strong><%= matchOdds.home ? Number(matchOdds.home).toFixed(2) : '-' %></strong>
            <small><%= matchOdds.bookmaker || 'Bookmaker' %></small>
          </aside>
        </article>
        <article>
          <div>
            <span>1X2</span>
            <h3>Match nul</h3>
          </div>
          <aside>
            <strong><%= matchOdds.draw ? Number(matchOdds.draw).toFixed(2) : '-' %></strong>
            <small><%= matchOdds.bookmaker || 'Bookmaker' %></small>
          </aside>
        </article>
        <article>
          <div>
            <span>1X2</span>
            <h3><%= safeMatch.away_team || 'Extérieur' %> gagne</h3>
          </div>
          <aside>
            <strong><%= matchOdds.away ? Number(matchOdds.away).toFixed(2) : '-' %></strong>
            <small><%= matchOdds.bookmaker || 'Bookmaker' %></small>
          </aside>
        </article>
      </div>
    <% } else if (allRecommendations.length) { %>
      <div class="analysis-v2-pronos-list analysis-v2-odds-table">
        <% allRecommendations.slice(0, 6).forEach((recommendation) => { %>
          <article>
            <div>
              <span><%= recommendation.market || recommendation.recommendation_type || 'Marché' %></span>
              <h3><%= recommendation.title %></h3>
            </div>
            <aside>
              <strong><%= recommendation.odds ? Number(recommendation.odds).toFixed(2) : '-' %></strong>
              <small><%= recommendation.bookmaker || 'Bookmaker' %></small>
            </aside>
          </article>
        <% }) %>
      </div>
    <% } else { %>
      <div class="analysis-v2-empty-note">
        <h3>Cotes indisponibles</h3>
        <p>TopStats attend une cote exploitable avant d’afficher un marché.</p>
      </div>
    <% } %>
  </section>

  <% if (!pageAnalysisLocked && !isFinishedMatchPage) { %>
  <section class="analysis-v2-card analysis-v2-match-analysis analysis-v2-tab-panel" data-analysis-panel="resume">
    <div class="analysis-v2-section-title">
      <div>
        <p class="eyebrow">Análisis del partido</p>
        <h2><%= displayAnalysis.title %></h2>
        <p>La lecture de TopStats sur le rapport de force, le rythme attendu et les détails qui peuvent faire basculer le match.</p>
      </div>
    </div>

    <div class="analysis-v2-prose">
      <% professionalAnalysisParagraphs.forEach((paragraph, index) => { %>
        <p class="<%= index === 0 ? 'lead' : '' %>"><%= paragraph %></p>
      <% }) %>
    </div>
  </section>
  <% } %>

  <p class="disclaimer analysis-v2-disclaimer">TopStats est une aide à la décision. Les analyses et recommandations ne garantissent jamais un résultat.</p>
</main>

<% if (!pageEmbeddedAnalysis) { %>
  <%- include('../partials/bottom-nav') %>
  <%- include('../partials/footer') %>
<% } else { %>
  <script src="/js/app.js?v=<%= assetVersion || '1' %>-desktop-inline-css715"></script>
  <script src="/i18n/client.js?v=<%= assetVersion || '1' %>&lang=<%= typeof locale !== 'undefined' ? locale : 'es' %>"></script>
</body>
</html>
<% } %>
