{"id":345,"date":"2026-06-12T21:08:51","date_gmt":"2026-06-12T21:08:51","guid":{"rendered":"https:\/\/profilesm.com\/?page_id=345"},"modified":"2026-06-29T05:30:36","modified_gmt":"2026-06-29T05:30:36","slug":"polla","status":"publish","type":"page","link":"https:\/\/profilesm.com\/es\/polla\/","title":{"rendered":"Polla"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"345\" class=\"elementor elementor-345\" data-elementor-post-type=\"page\">\n\t\t\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-6f66ab1 e-flex e-con-boxed e-con e-parent\" data-id=\"6f66ab1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3554899 elementor-widget elementor-widget-html\" data-id=\"3554899\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Polla Mundialista 2026 (Supabase)<\/title>\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700;800&display=swap\" rel=\"stylesheet\">\n  <!-- Supabase SDK via CDN -->\n  <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"><\/script>\n  \n  <style>\n    :root {\n      --bg: #0f172a;\n      --card-bg: #1e293b;\n      --text: #f8fafc;\n      --text-muted: #94a3b8;\n      --primary: #3b82f6;\n      --primary-hover: #2563eb;\n      --accent: #10b981;\n      --danger: #ef4444;\n      --border: #334155;\n      --input-bg: #0f172a;\n    }\n    * { box-sizing: border-box; }\n    body {\n      margin: 0;\n      font-family: 'Inter', sans-serif;\n      background-color: var(--bg);\n      color: var(--text);\n      padding-bottom: 60px;\n    }\n    \/* --- Navbar y Tabs --- *\/\n    header {\n      background: rgba(30, 41, 59, 0.9);\n      backdrop-filter: blur(10px);\n      position: sticky;\n      top: 0;\n      z-index: 100;\n      padding: 16px 24px;\n      border-bottom: 1px solid var(--border);\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      flex-wrap: wrap;\n      gap: 12px;\n    }\n    h1 {\n      margin: 0;\n      font-size: 24px;\n      font-weight: 800;\n      background: linear-gradient(90deg, #38bdf8, #818cf8);\n      -webkit-background-clip: text;\n      -webkit-text-fill-color: transparent;\n    }\n    .nav-tabs { display: flex; gap: 10px; }\n    .tab-btn { background: transparent; border: 1px solid var(--border); color: var(--text-muted); padding: 8px 16px; border-radius: 8px; font-weight: 600; cursor: pointer; transition: all 0.2s; }\n    .tab-btn.active, .tab-btn:hover { background: var(--border); color: var(--text); }\n    .user-actions { display: flex; align-items: center; gap: 16px; }\n    .score-board { background: var(--primary); padding: 6px 14px; border-radius: 20px; font-weight: 700; font-size: 16px; box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4); }\n    .logout-btn { background: transparent; border: 1px solid var(--danger); color: var(--danger); padding: 6px 12px; border-radius: 6px; cursor: pointer; font-weight: 600; }\n    \/* --- Modals (Auth) --- *\/\n    .modal-overlay {\n      position: fixed; top: 0; left: 0; right: 0; bottom: 0;\n      background: rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center;\n      z-index: 1000; backdrop-filter: blur(5px);\n    }\n    .modal {\n      background: var(--card-bg); padding: 32px; border-radius: 16px; width: 90%; max-width: 400px;\n      text-align: center; border: 1px solid var(--border);\n    }\n    .modal h2 { margin-top: 0; margin-bottom: 24px; }\n    \n    .modal input {\n      width: 100%; padding: 12px; margin-bottom: 12px; background: var(--input-bg);\n      border: 1px solid var(--border); color: var(--text); border-radius: 8px;\n    }\n    .auth-btn { width: 100%; padding: 12px; color: white; border: none; border-radius: 8px; font-weight: 700; font-size: 16px; cursor: pointer; margin-bottom: 12px; transition: opacity 0.2s; }\n    .auth-btn:hover { opacity: 0.9; }\n    .btn-login { background: var(--primary); }\n    .btn-register { background: var(--accent); }\n    .btn-local { background: #64748b; margin-top: 12px; }\n    \n    .error-msg { color: var(--danger); font-size: 14px; margin-bottom: 12px; min-height: 20px; }\n    \/* --- Vistas Principales --- *\/\n    .view { display: none; }\n    .view.active { display: block; }\n    .container { max-width: 1000px; margin: 32px auto; padding: 0 16px; }\n    \/* Filtros y Grid *\/\n    .filters { display: flex; gap: 12px; margin-bottom: 24px; overflow-x: auto; padding-bottom: 8px; }\n    .filter-btn { background: var(--card-bg); border: 1px solid var(--border); color: var(--text); padding: 8px 16px; border-radius: 20px; cursor: pointer; font-weight: 600; white-space: nowrap; }\n    .filter-btn.active { background: var(--primary); border-color: var(--primary); }\n    .matches-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }\n    .match-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; }\n    .match-card.finished { opacity: 0.85; }\n    .card-header { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-muted); margin-bottom: 16px; font-weight: 600; text-transform: uppercase; }\n    .status.live { color: #f87171; animation: pulse 2s infinite; }\n    .status.finished { color: var(--accent); }\n    .team-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }\n    .team-info { display: flex; align-items: center; gap: 12px; }\n    .flag { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; background: #fff; }\n    .team-name { font-weight: 600; font-size: 16px; }\n    .score-inputs { display: flex; align-items: center; gap: 8px; }\n    .score-input { width: 44px; height: 44px; background: var(--input-bg); border: 2px solid var(--border); border-radius: 8px; color: var(--text); font-size: 20px; font-weight: 700; text-align: center; }\n    .score-input:focus { outline: none; border-color: var(--primary); }\n    .score-input:disabled { background: transparent; border-color: transparent; opacity: 1; cursor: not-allowed; }\n    .real-score { font-size: 20px; font-weight: 800; background: rgba(0,0,0,0.3); padding: 4px 12px; border-radius: 8px; color: var(--text-muted); }\n    .card-footer { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }\n    .points-badge { font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 12px; background: var(--border); color: var(--text-muted); }\n    .points-badge.exact { background: var(--accent); color: #fff; }\n    .points-badge.winner { background: var(--primary); color: #fff; }\n    .save-btn { background: var(--primary); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-weight: 600; cursor: pointer; }\n    .save-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n    \/* Ranking *\/\n    .ranking-table { width: 100%; border-collapse: collapse; background: var(--card-bg); border-radius: 12px; overflow: hidden; }\n    .ranking-table th, .ranking-table td { padding: 16px; text-align: left; border-bottom: 1px solid var(--border); }\n    .ranking-table th { background: rgba(0,0,0,0.2); font-weight: 700; color: var(--text-muted); text-transform: uppercase; font-size: 12px; }\n    .ranking-table tr:hover { background: rgba(255,255,255,0.02); }\n    .rank-pos { font-size: 24px; font-weight: 800; color: var(--text-muted); width: 50px; }\n    .rank-pos.gold { color: #fbbf24; }\n    .rank-pos.silver { color: #94a3b8; }\n    .rank-pos.bronze { color: #b45309; }\n    \/* Toast *\/\n    .toast { position: fixed; bottom: 24px; right: 24px; background: var(--accent); color: white; padding: 12px 24px; border-radius: 8px; font-weight: 600; transform: translateY(100px); opacity: 0; transition: all 0.3s; z-index: 1000; }\n    .toast.show { transform: translateY(0); opacity: 1; }\n    @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }\n    .loading-container { text-align: center; padding: 60px 20px; color: var(--text-muted); font-size: 18px; font-weight: 600; }\n  <\/style>\n<\/head>\n<body>\n  <!-- Auth Modal -->\n  <div class=\"modal-overlay\" id=\"auth-modal\" style=\"display: none;\">\n    <div class=\"modal\">\n      <h2>Ingresar a la Polla<\/h2>\n      <div id=\"auth-error\" class=\"error-msg\"><\/div>\n      <input type=\"text\" id=\"auth-name\" placeholder=\"Tu Nombre (Solo para Registro)\">\n      <input type=\"email\" id=\"auth-email\" placeholder=\"Correo Electr\u00f3nico\">\n      <input type=\"password\" id=\"auth-password\" placeholder=\"Contrase\u00f1a\">\n      \n      <button class=\"auth-btn btn-login\" id=\"btn-login\">Iniciar Sesi\u00f3n<\/button>\n      <button class=\"auth-btn btn-register\" id=\"btn-register\">Crear Cuenta<\/button>\n    <\/div>\n  <\/div>\n  <header>\n    <h1>Polla Mundialista 2026<\/h1>\n    <div class=\"nav-tabs\" id=\"nav-tabs\" style=\"display:none;\">\n      <button class=\"tab-btn active\" data-view=\"view-predictions\">Mis Predicciones<\/button>\n      <button class=\"tab-btn\" data-view=\"view-ranking\">Ranking Global<\/button>\n    <\/div>\n    <div class=\"user-actions\" id=\"user-actions\" style=\"display:none;\">\n      <button id=\"btn-refresh-api\" class=\"tab-btn\" style=\"border:none; cursor:pointer;\" title=\"Forzar actualizaci\u00f3n de datos\">\ud83d\udd04 Actualizar<\/button>\n      <button id=\"btn-admin-toggle\" class=\"tab-btn\" style=\"display:none; background:var(--accent); color:#fff; border:none;\">Modo Admin<\/button>\n      <div class=\"score-board\"><span id=\"user-name-display\"><\/span>: <span id=\"total-points\">0<\/span> pts<\/div>\n      <button class=\"logout-btn\" id=\"btn-logout\">Salir<\/button>\n    <\/div>\n  <\/header>\n  <div class=\"container view active\" id=\"view-predictions\">\n    <div class=\"filters\" id=\"filters-container\">\n      <button class=\"filter-btn active\" data-filter=\"all\">Todos<\/button>\n      <button class=\"filter-btn\" data-filter=\"SCHEDULED\">Por jugar<\/button>\n      <button class=\"filter-btn\" data-filter=\"FINISHED\">Terminados<\/button>\n    <\/div>\n    <div class=\"matches-grid\" id=\"matches-grid\">\n      <div class=\"loading-container\">Cargando partidos...<\/div>\n    <\/div>\n  <\/div>\n  <div class=\"container view\" id=\"view-ranking\">\n    <table class=\"ranking-table\">\n      <thead>\n        <tr>\n          <th>Pos<\/th>\n          <th>Jugador<\/th>\n          <th>Plenos (3pts)<\/th>\n          <th>Aciertos (1pt)<\/th>\n          <th>Puntos Totales<\/th>\n        <\/tr>\n      <\/thead>\n      <tbody id=\"ranking-body\">\n        <tr><td colspan=\"5\" class=\"loading-container\">Calculando posiciones...<\/td><\/tr>\n      <\/tbody>\n    <\/table>\n  <\/div>\n  <div class=\"toast\" id=\"toast\">\u2705 Guardado exitosamente<\/div>\n  <script>\n    \/\/ IMPORTANTE: REEMPLAZA ESTOS VALORES CON TU PROYECTO DE SUPABASE\n    const SUPABASE_URL = \"https:\/\/ukfkppgbnwszwxnqnejl.supabase.co\";\n    const SUPABASE_ANON_KEY = \"sb_publishable_6MoDp1PRwhujIwwL7rs06g_pqlAKy47\";\n    const ADMIN_EMAIL = \"dpareja@mgpgroup.co\";\n    const isSupabaseConfigured = SUPABASE_URL !== \"TU_SUPABASE_URL\" && window.supabase;\n    let supabaseClient = null;\n    let currentUser = null;\n    let localMode = false;\n    let allMatches = [];\n    let userPredictions = {};\n    let manualResults = {};\n    let isAdminMode = false;\n    let userName = \"Jugador\";\n    \n    if (isSupabaseConfigured) {\n      supabaseClient = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);\n    } else {\n      console.warn(\"SUPABASE NO CONFIGURADO: Modo Local \/ Simulaci\u00f3n habilitado.\");\n    }\n    const API_URL = 'https:\/\/raw.githubusercontent.com\/openfootball\/worldcup.json\/master\/2026\/worldcup.json';\n    const flagMap = {\n      \/\/ Norteam\u00e9rica, Centroam\u00e9rica y Caribe (CONCACAF)\n      \"USA\": \"us\", \"United States\": \"us\", \"Canada\": \"ca\", \"Mexico\": \"mx\", \"Costa Rica\": \"cr\", \"Panama\": \"pa\",\n      \"Jamaica\": \"jm\", \"Honduras\": \"hn\", \"El Salvador\": \"sv\", \"Guatemala\": \"gt\", \"Trinidad and Tobago\": \"tt\",\n      \"Haiti\": \"ht\", \"Cura\u00e7ao\": \"cw\", \"Cuba\": \"cu\", \"Martinique\": \"mq\", \"Nicaragua\": \"ni\", \"Dominican Republic\": \"do\",\n      \/\/ Sudam\u00e9rica (CONMEBOL)\n      \"Argentina\": \"ar\", \"Brazil\": \"br\", \"Uruguay\": \"uy\", \"Colombia\": \"co\", \"Ecuador\": \"ec\", \"Peru\": \"pe\",\n      \"Chile\": \"cl\", \"Paraguay\": \"py\", \"Venezuela\": \"ve\", \"Bolivia\": \"bo\",\n      \/\/ Europa (UEFA)\n      \"France\": \"fr\", \"Germany\": \"de\", \"Spain\": \"es\", \"England\": \"gb-eng\", \"Portugal\": \"pt\", \"Italy\": \"it\",\n      \"Netherlands\": \"nl\", \"Belgium\": \"be\", \"Croatia\": \"hr\", \"Denmark\": \"dk\", \"Sweden\": \"se\", \"Poland\": \"pl\",\n      \"Serbia\": \"rs\", \"Switzerland\": \"ch\", \"Wales\": \"gb-wls\", \"Scotland\": \"gb-sct\", \"Republic of Ireland\": \"ie\",\n      \"Ireland\": \"ie\", \"Northern Ireland\": \"gb-nir\", \"Norway\": \"no\", \"Turkey\": \"tr\", \"T\u00fcrkiye\": \"tr\", \"Greece\": \"gr\",\n      \"Ukraine\": \"ua\", \"Austria\": \"at\", \"Czech Republic\": \"cz\", \"Czechia\": \"cz\", \"Hungary\": \"hu\", \"Romania\": \"ro\",\n      \"Slovakia\": \"sk\", \"Slovenia\": \"si\", \"Bosnia & Herzegovina\": \"ba\", \"Bosnia and Herzegovina\": \"ba\",\n      \"Albania\": \"al\", \"Bulgaria\": \"bg\", \"Finland\": \"fi\", \"Iceland\": \"is\", \"Israel\": \"il\", \"Georgia\": \"ge\",\n      \"Armenia\": \"am\", \"Azerbaijan\": \"az\", \"Kazakhstan\": \"kz\", \"Cyprus\": \"cy\", \"Estonia\": \"ee\", \"Latvia\": \"lv\",\n      \"Lithuania\": \"lt\", \"Montenegro\": \"me\", \"North Macedonia\": \"mk\",\n      \/\/ \u00c1frica (CAF)\n      \"Senegal\": \"sn\", \"Morocco\": \"ma\", \"Cameroon\": \"cm\", \"Ghana\": \"gh\", \"Tunisia\": \"tn\", \"Nigeria\": \"ng\",\n      \"Egypt\": \"eg\", \"Algeria\": \"dz\", \"Ivory Coast\": \"ci\", \"C\u00f4te d'Ivoire\": \"ci\", \"Mali\": \"ml\", \"South Africa\": \"za\",\n      \"Burkina Faso\": \"bf\", \"DR Congo\": \"cd\", \"Guinea\": \"gn\", \"Cape Verde\": \"cv\", \"Zambia\": \"zm\", \"Uganda\": \"ug\",\n      \"Gabon\": \"ga\", \"Angola\": \"ao\", \"Equatorial Guinea\": \"gq\", \"Mauritania\": \"mr\",\n      \/\/ Asia (AFC)\n      \"Japan\": \"jp\", \"Iran\": \"ir\", \"IR Iran\": \"ir\", \"South Korea\": \"kr\", \"Korea Republic\": \"kr\", \"Saudi Arabia\": \"sa\",\n      \"Australia\": \"au\", \"Qatar\": \"qa\", \"UAE\": \"ae\", \"United Arab Emirates\": \"ae\", \"Iraq\": \"iq\", \"Oman\": \"om\",\n      \"China\": \"cn\", \"China PR\": \"cn\", \"Syria\": \"sy\", \"Uzbekistan\": \"uz\", \"Vietnam\": \"vn\", \"Lebanon\": \"lb\",\n      \"Jordan\": \"jo\", \"Bahrain\": \"bh\", \"Palestine\": \"ps\", \"India\": \"in\", \"Tajikistan\": \"tj\", \"Thailand\": \"th\",\n      \"North Korea\": \"kp\", \"Korea DPR\": \"kp\", \"Indonesia\": \"id\", \"Malaysia\": \"my\", \"Kuwait\": \"kw\",\n      \/\/ Ocean\u00eda (OFC)\n      \"New Zealand\": \"nz\", \"Fiji\": \"fj\", \"Solomon Islands\": \"sb\", \"Tahiti\": \"pf\", \"Vanuatu\": \"vu\", \"Papua New Guinea\": \"pg\",\n      \"New Caledonia\": \"nc\"\n    };\n    function getFlagUrl(tName) {\n      if (!tName || tName === 'Por definir') return 'https:\/\/upload.wikimedia.org\/wikipedia\/commons\/2\/2f\/Missing_flag.png';\n      const c = flagMap[tName.trim()];\n      return c ? `https:\/\/flagcdn.com\/w80\/${c}.png` : 'https:\/\/upload.wikimedia.org\/wikipedia\/commons\/2\/2f\/Missing_flag.png';\n    }\n    function parseMatchDate(dateStr, timeStr) {\n      if (!dateStr) return new Date();\n      if (dateStr.includes('T')) return new Date(dateStr);\n      if (dateStr.length !== 10) return new Date(dateStr);\n      if (!timeStr) return new Date(dateStr + 'T12:00:00Z');\n      \n      let timePart = \"12:00\";\n      let offset = \"Z\";\n      const tMatch = timeStr.match(\/(\\d{2}:\\d{2})\/);\n      if (tMatch) timePart = tMatch[1];\n      const oMatch = timeStr.match(\/UTC([+-]\\d+)\/);\n      if (oMatch) {\n        let num = parseInt(oMatch[1]);\n        let sign = num < 0 ? '-' : '+';\n        let val = Math.abs(num);\n        offset = sign + (val < 10 ? '0'+val : val) + ':00';\n      }\n      return new Date(`${dateStr}T${timePart}:00${offset}`);\n    }\n    \/\/ --- L\u00d3GICA CORE ---\n    async function loadAPI() {\n      const res = await fetch(API_URL, { cache: 'no-store' });\n      const data = await res.json();\n      allMatches = data.matches || data;\n      allMatches.sort((a,b) => {\n        return parseMatchDate(a.utcDate || a.date, a.time) - parseMatchDate(b.utcDate || b.date, b.time);\n      });\n      allMatches.forEach((m, i) => { if (!m.id) m.id = `match_${i}`; });\n    }\n    function calculatePoints(predHome, predAway, rHome, rAway) {\n      if (rHome === null || rAway === null || predHome === '' || predAway === '') return null;\n      const pH = parseInt(predHome), pA = parseInt(predAway), rH = parseInt(rHome), rA = parseInt(rAway);\n      if (pH === rH && pA === rA) return 3;\n      const pd = pH - pA, rd = rH - rA;\n      if ((pd > 0 && rd > 0) || (pd < 0 && rd < 0) || (pd === 0 && rd === 0)) return 1;\n      return 0;\n    }\n    function evaluatePredictions(preds) {\n      let total = 0, exactos = 0, parciales = 0;\n      allMatches.forEach(m => {\n        const manual = manualResults[m.id];\n        const rHome = manual ? manual.home : (m.score?.fullTime?.home ?? m.homeScore ?? m.score1 ?? null);\n        const rAway = manual ? manual.away : (m.score?.fullTime?.away ?? m.awayScore ?? m.score2 ?? null);\n        const saved = preds[m.id] || { home: '', away: '' };\n        if(rHome !== null) {\n          const pts = calculatePoints(saved.home, saved.away, rHome, rAway);\n          if(pts === 3) exactos++;\n          if(pts === 1) parciales++;\n          if(pts !== null) total += pts;\n        }\n      });\n      return { total, exactos, parciales };\n    }\n    \/\/ --- DOM \/ RENDERING ---\n    \n    function renderMatches(filter = 'all') {\n      const grid = document.getElementById('matches-grid');\n      grid.innerHTML = '';\n      \n      let filtered = allMatches;\n      if(filter === 'SCHEDULED') filtered = allMatches.filter(m => (m.status||'').toUpperCase() !== 'FINISHED' && (m.status||'').toUpperCase() !== 'AWARDED');\n      if(filter === 'FINISHED') filtered = allMatches.filter(m => (m.status||'').toUpperCase() === 'FINISHED' || (m.status||'').toUpperCase() === 'AWARDED');\n      filtered.forEach(m => {\n        const dObj = parseMatchDate(m.utcDate || m.date, m.time);\n        \n        \/\/ El partido se bloquea 10 minutos antes de la hora programada\n        const lockoutTime = new Date(dObj.getTime() - 10 * 60 * 1000);\n        const isPast = new Date() >= lockoutTime;\n        \n        const dayOptions = { weekday: 'short', day: 'numeric', month: 'short' };\n        let dStr = dObj.toLocaleDateString('es-ES', dayOptions);\n        dStr = dStr.charAt(0).toUpperCase() + dStr.slice(1).replace('.', '');\n        \n        const timeOptions = { hour: 'numeric', minute: '2-digit', hour12: true };\n        let tStr = dObj.toLocaleTimeString('es-ES', timeOptions);\n        \n        const st = (m.status||'SCHEDULED').toUpperCase();\n        const isFin = (st==='FINISHED' || st==='AWARDED');\n        const isLive = (st==='IN_PLAY' || st==='LIVE');\n        \n        const manual = manualResults[m.id];\n        const rH = manual ? manual.home : (m.score?.fullTime?.home ?? m.homeScore ?? m.score1 ?? null);\n        const rA = manual ? manual.away : (m.score?.fullTime?.away ?? m.awayScore ?? m.score2 ?? null);\n        const hName = m.homeTeam?.name || m.homeTeam || m.team1?.name || m.team1 || 'Por definir';\n        const aName = m.awayTeam?.name || m.awayTeam || m.team2?.name || m.team2 || 'Por definir';\n        \n        const saved = userPredictions[m.id] || {home:'',away:''};\n        const canEdit = !isPast && !isFin && !isLive && hName !== 'Por definir';\n        let ptsHtml = '<span class=\"points-badge\">Pendiente<\/span>';\n        if(isFin || rH !== null) {\n          const pts = calculatePoints(saved.home, saved.away, rH, rA);\n          if(pts === 3) ptsHtml = '<span class=\"points-badge exact\">+3 Pts (Pleno)<\/span>';\n          else if(pts === 1) ptsHtml = '<span class=\"points-badge winner\">+1 Pt (Ganador)<\/span>';\n          else if(pts === 0) ptsHtml = '<span class=\"points-badge\" style=\"background:var(--danger);color:#fff\">0 Pts (Fallo)<\/span>';\n          else ptsHtml = '<span class=\"points-badge\">Sin predicci\u00f3n<\/span>';\n        }\n        let homeInput = '', awayInput = '', buttonHtml = '';\n        \n        if (isAdminMode && hName !== 'Por definir') {\n          homeInput = `<input type=\"number\" id=\"admin_h_${m.id}\" class=\"score-input\" value=\"${rH!==null?rH:''}\" style=\"border-color:var(--accent)\">`;\n          awayInput = `<input type=\"number\" id=\"admin_a_${m.id}\" class=\"score-input\" value=\"${rA!==null?rA:''}\" style=\"border-color:var(--accent)\">`;\n          buttonHtml = `<button class=\"save-btn\" style=\"background:var(--accent)\" id=\"btn_admin_save_${m.id}\">Fijar Oficial<\/button>`;\n          if (manual) {\n            buttonHtml += `<button class=\"save-btn\" style=\"background:var(--border); margin-left:8px;\" id=\"btn_admin_del_${m.id}\">Auto<\/button>`;\n          }\n        } else {\n          homeInput = `${(isFin||isLive||rH!==null) ? `<div class=\"real-score\">${rH!==null?rH:'-'}<\/div>` : ''}\n                       <input type=\"number\" id=\"h_${m.id}\" class=\"score-input\" value=\"${saved.home}\" ${canEdit?'':'disabled'}>`;\n          awayInput = `${(isFin||isLive||rA!==null) ? `<div class=\"real-score\">${rA!==null?rA:'-'}<\/div>` : ''}\n                       <input type=\"number\" id=\"a_${m.id}\" class=\"score-input\" value=\"${saved.away}\" ${canEdit?'':'disabled'}>`;\n          buttonHtml = canEdit ? `<button class=\"save-btn\" id=\"btn_save_${m.id}\">Guardar<\/button>` : '';\n        }\n        const div = document.createElement('div');\n        div.className = `match-card ${isFin||rH!==null?'finished':''}`;\n        div.innerHTML = `\n          <div class=\"card-header\">\n            <span>${dStr} \u2022 ${m.group || m.stage || m.round || 'Grupos'}<\/span>\n            <span class=\"status ${isLive?'live':isFin||rH!==null?'finished':''}\">${isLive?'En Vivo '+tStr:isFin||rH!==null?'Finalizado':tStr}<\/span>\n          <\/div>\n          <div class=\"team-row\">\n            <div class=\"team-info\"><img decoding=\"async\" src=\"${getFlagUrl(hName)}\" class=\"flag\"><span class=\"team-name\">${hName}<\/span><\/div>\n            <div class=\"score-inputs\">${homeInput}<\/div>\n          <\/div>\n          <div class=\"team-row\">\n            <div class=\"team-info\"><img decoding=\"async\" src=\"${getFlagUrl(aName)}\" class=\"flag\"><span class=\"team-name\">${aName}<\/span><\/div>\n            <div class=\"score-inputs\">${awayInput}<\/div>\n          <\/div>\n          <div class=\"card-footer\">\n            ${isAdminMode ? '<span class=\"points-badge\" style=\"background:transparent; color:var(--accent)\">MODO ADMIN<\/span>' : ptsHtml}\n            ${buttonHtml}\n          <\/div>\n        `;\n        grid.appendChild(div);\n        \n        if (isAdminMode && hName !== 'Por definir') {\n          document.getElementById(`btn_admin_save_${m.id}`).addEventListener('click', () => saveAdminMatch(m.id));\n          if (manual) document.getElementById(`btn_admin_del_${m.id}`).addEventListener('click', () => deleteAdminMatch(m.id));\n        } else if (!isAdminMode && canEdit) {\n          document.getElementById(`btn_save_${m.id}`).addEventListener('click', () => saveMatch(m.id));\n        }\n      });\n      const result = evaluatePredictions(userPredictions);\n      document.getElementById('total-points').innerText = result.total;\n    }\n    async function renderRanking() {\n      const tbody = document.getElementById('ranking-body');\n      tbody.innerHTML = '<tr><td colspan=\"5\" class=\"loading-container\">Cargando ranking mundial...<\/td><\/tr>';\n      \n      let usersList = [];\n      if(isSupabaseConfigured && !localMode) {\n        const { data, error } = await supabaseClient.from('user_predictions').select('name, predictions');\n        if(!error && data) {\n          data.forEach(row => {\n            const stats = evaluatePredictions(row.predictions || {});\n            usersList.push({ name: row.name || 'An\u00f3nimo', stats });\n          });\n        }\n      } else {\n        const myStats = evaluatePredictions(userPredictions);\n        usersList.push({ name: userName, stats: myStats });\n      }\n      usersList.sort((a,b) => b.stats.total - a.stats.total);\n      \n      tbody.innerHTML = '';\n      usersList.forEach((u, idx) => {\n        let posClass = idx===0 ? 'gold' : idx===1 ? 'silver' : idx===2 ? 'bronze' : '';\n        tbody.innerHTML += `\n          <tr>\n            <td class=\"rank-pos ${posClass}\">#${idx+1}<\/td>\n            <td style=\"font-weight:600\">${u.name}<\/td>\n            <td>${u.stats.exactos}<\/td>\n            <td>${u.stats.parciales}<\/td>\n            <td style=\"font-weight:800; color:var(--primary)\">${u.stats.total}<\/td>\n          <\/tr>\n        `;\n      });\n    }\n    \/\/ --- BASE DE DATOS Y ESTADO ---\n    async function saveMatch(matchId) {\n      const hVal = document.getElementById(`h_${matchId}`).value;\n      const aVal = document.getElementById(`a_${matchId}`).value;\n      userPredictions[matchId] = { home: hVal, away: aVal };\n      \n      if(isSupabaseConfigured && !localMode && currentUser) {\n        await supabaseClient.from('user_predictions').upsert({\n          id: currentUser.id,\n          name: userName,\n          predictions: userPredictions\n        });\n      } else {\n        localStorage.setItem('pollaPredictions_SB', JSON.stringify(userPredictions));\n      }\n      \n      const t = document.getElementById('toast');\n      t.classList.add('show');\n      setTimeout(()=> t.classList.remove('show'), 2000);\n      \n      const result = evaluatePredictions(userPredictions);\n      document.getElementById('total-points').innerText = result.total;\n    }\n    async function deleteAdminMatch(matchId) {\n      delete manualResults[matchId];\n      if(isSupabaseConfigured && !localMode) {\n        await supabaseClient.from('manual_results').delete().eq('match_id', matchId);\n      }\n      const t = document.getElementById('toast');\n      const originalText = t.innerText;\n      t.innerText = \"Restaurado a modo autom\u00e1tico\";\n      t.classList.add('show');\n      setTimeout(()=> { t.classList.remove('show'); setTimeout(() => t.innerText = originalText, 300); }, 2000);\n      renderMatches();\n      if (document.getElementById('view-ranking').classList.contains('active')) renderRanking();\n    }\n    async function saveAdminMatch(matchId) {\n      const hVal = document.getElementById(`admin_h_${matchId}`).value;\n      const aVal = document.getElementById(`admin_a_${matchId}`).value;\n      if (hVal === '' || aVal === '') return alert(\"Ingresa ambos goles para fijar el resultado oficial.\");\n      \n      const hScore = parseInt(hVal);\n      const aScore = parseInt(aVal);\n      manualResults[matchId] = { home: hScore, away: aScore };\n      \n      if(isSupabaseConfigured && !localMode) {\n        await supabaseClient.from('manual_results').upsert({\n          match_id: matchId,\n          home_score: hScore,\n          away_score: aScore\n        });\n      }\n      \n      const t = document.getElementById('toast');\n      const originalText = t.innerText;\n      t.innerText = \"\u2b50 Resultado Oficial Guardado\";\n      t.classList.add('show');\n      setTimeout(()=> { t.classList.remove('show'); setTimeout(() => t.innerText = originalText, 300); }, 2000);\n      \n      renderMatches();\n      if (document.getElementById('view-ranking').classList.contains('active')) renderRanking();\n    }\n    async function launchApp() {\n      document.getElementById('auth-modal').style.display = 'none';\n      document.getElementById('nav-tabs').style.display = 'flex';\n      document.getElementById('user-actions').style.display = 'flex';\n      document.getElementById('user-name-display').innerText = userName;\n      if(isSupabaseConfigured && !localMode && currentUser) {\n        \n        \/\/ Cargar resultados manuales del admin\n        const { data: manualData } = await supabaseClient.from('manual_results').select('*');\n        if (manualData) {\n          manualData.forEach(r => manualResults[r.match_id] = { home: r.home_score, away: r.away_score });\n        }\n        \n        \/\/ Mostrar bot\u00f3n Admin si es el correo autorizado\n        if (currentUser.email === ADMIN_EMAIL) {\n          document.getElementById('btn-admin-toggle').style.display = 'block';\n        }\n        const { data, error } = await supabaseClient.from('user_predictions').select('predictions, name').eq('id', currentUser.id).single();\n        if(data) {\n          userPredictions = data.predictions || {};\n          \n          if(data.name && data.name !== \"Jugador\") {\n            userName = data.name;\n          } else if (currentUser.email) {\n            userName = currentUser.email.split('@')[0];\n            \/\/ Reparar base de datos si qued\u00f3 con el nombre por defecto (requiere await para ejecutarse)\n            await supabaseClient.from('user_predictions').update({ name: userName }).eq('id', currentUser.id);\n          }\n          \n          document.getElementById('user-name-display').innerText = userName;\n        } else {\n          \/\/ El usuario existe en Auth pero NO en la tabla (ej. fallo de guardado previo por verificaci\u00f3n de email)\n          userName = currentUser.email ? currentUser.email.split('@')[0] : \"Jugador\";\n          document.getElementById('user-name-display').innerText = userName;\n          userPredictions = {};\n          \/\/ Reparar la cuenta creando su fila en la base de datos\n          await supabaseClient.from('user_predictions').upsert({ id: currentUser.id, name: userName, predictions: {} });\n        }\n      } else {\n        userPredictions = JSON.parse(localStorage.getItem('pollaPredictions_SB')) || {};\n      }\n      await loadAPI();\n      renderMatches();\n    }\n    \/\/ --- AUTHENTICATION (SUPABASE) ---\n    function showError(msg) {\n      document.getElementById('auth-error').innerText = msg;\n    }\n    document.getElementById('btn-login').addEventListener('click', async () => {\n      if(!isSupabaseConfigured) return showError(\"Supabase no est\u00e1 configurado. Usa Modo Local.\");\n      const email = document.getElementById('auth-email').value;\n      const password = document.getElementById('auth-password').value;\n      if(!email || !password) return showError(\"Completa email y contrase\u00f1a\");\n      \n      const { data, error } = await supabaseClient.auth.signInWithPassword({ email, password });\n      if(error) return showError(error.message);\n      \n      currentUser = data.user;\n      \n      \/\/ Fetch user name from db if exists\n      const { data: dbData } = await supabaseClient.from('user_predictions').select('name').eq('id', currentUser.id).single();\n      if(dbData && dbData.name) userName = dbData.name;\n      else userName = email.split('@')[0];\n      localMode = false;\n      launchApp();\n    });\n    document.getElementById('btn-register').addEventListener('click', async () => {\n      if(!isSupabaseConfigured) return showError(\"Supabase no est\u00e1 configurado. Usa Modo Local.\");\n      const name = document.getElementById('auth-name').value;\n      const email = document.getElementById('auth-email').value;\n      const password = document.getElementById('auth-password').value;\n      if(!name || !email || !password) return showError(\"Completa todos los campos\");\n      \n      const { data, error } = await supabaseClient.auth.signUp({ email, password });\n      if(error) return showError(error.message);\n      \n      currentUser = data.user;\n      userName = name;\n      \n      \/\/ Initialize row\n      await supabaseClient.from('user_predictions').upsert({ id: currentUser.id, name: userName, predictions: {} });\n      \n      localMode = false;\n      launchApp();\n    });\n    document.getElementById('btn-logout').addEventListener('click', async () => {\n      if(isSupabaseConfigured && !localMode) await supabaseClient.auth.signOut();\n      location.reload();\n    });\n    \/\/ --- INICIALIZACI\u00d3N ---\n    document.querySelectorAll('.tab-btn').forEach(btn => {\n      btn.addEventListener('click', (e) => {\n        document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));\n        e.target.classList.add('active');\n        document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));\n        const vId = e.target.dataset.view;\n        document.getElementById(vId).classList.add('active');\n        if(vId === 'view-ranking') renderRanking();\n      });\n    });\n    document.querySelectorAll('.filter-btn').forEach(btn => {\n      btn.addEventListener('click', (e) => {\n        document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));\n        e.target.classList.add('active');\n        renderMatches(e.target.dataset.filter);\n      });\n    });\n    document.getElementById('btn-refresh-api').addEventListener('click', async () => {\n      document.getElementById('btn-refresh-api').innerText = \"\u23f3\";\n      await loadAPI();\n      renderMatches();\n      if (document.getElementById('view-ranking').classList.contains('active')) renderRanking();\n      document.getElementById('btn-refresh-api').innerText = \"\ud83d\udd04 Actualizar\";\n    });\n    document.getElementById('btn-admin-toggle').addEventListener('click', (e) => {\n      isAdminMode = !isAdminMode;\n      e.target.innerText = isAdminMode ? \"Salir de Admin\" : \"Modo Admin\";\n      e.target.style.background = isAdminMode ? \"#334155\" : \"var(--accent)\";\n      renderMatches();\n    });\n    \/\/ Check session on load\n    if (isSupabaseConfigured) {\n      supabaseClient.auth.getSession().then(({ data: { session } }) => {\n        if (session) {\n          currentUser = session.user;\n          localMode = false;\n          launchApp();\n        } else {\n          document.getElementById('auth-modal').style.display = 'flex';\n        }\n      });\n    } else {\n      document.getElementById('auth-modal').style.display = 'flex';\n    }\n  <\/script>\n<\/body>\n<\/html>\n\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Polla Mundialista 2026 (Supabase) Ingresar a la Polla Iniciar Sesi\u00f3n Crear Cuenta Polla Mundialista 2026 Mis Predicciones Ranking Global \ud83d\udd04&#8230;<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-345","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/pages\/345","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/comments?post=345"}],"version-history":[{"count":10,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/pages\/345\/revisions"}],"predecessor-version":[{"id":403,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/pages\/345\/revisions\/403"}],"wp:attachment":[{"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/media?parent=345"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/categories?post=345"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/profilesm.com\/es\/wp-json\/wp\/v2\/tags?post=345"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}