{"id":10,"date":"2026-04-28T06:29:56","date_gmt":"2026-04-28T06:29:56","guid":{"rendered":"https:\/\/totoveikkaus.fi\/?page_id=10"},"modified":"2026-05-26T09:12:16","modified_gmt":"2026-05-26T09:12:16","slug":"aloitus","status":"publish","type":"page","link":"https:\/\/totoveikkaus.fi\/","title":{"rendered":"Aloitus"},"content":{"rendered":"    <div class=\"kv-kalenteri-wrapper\">\n        <!-- V\u00e4lilehtien navigaatio -->\n        <div class=\"kv-tabs\">\n                            <button class=\"kv-tab-btn active\" data-country=\"suomi\" onclick=\"switchCountryTab('suomi')\">\ud83c\uddeb\ud83c\uddee Suomi<\/button>\n                                            <\/div>\n\n        <!-- Ravit T\u00e4n\u00e4\u00e4n Nostoalue -->\n        <div class=\"kv-box-today\">\n            <h2 id=\"kv-today-title\">Ravit T\u00e4n\u00e4\u00e4n<\/h2>\n            <div id=\"kv-today-container\" class=\"kv-grid-today\">\n                <p>Ladataan t\u00e4m\u00e4n p\u00e4iv\u00e4n l\u00e4ht\u00f6j\u00e4...<\/p>\n            <\/div>\n        <\/div>\n\n        <!-- Hakukentt\u00e4 -->\n        <input type=\"text\" id=\"kv-calendar-search\" class=\"kv-search-input\" placeholder=\"Hae radan nimell\u00e4 tai paikkakunnalla...\">\n\n        <!-- Kuukausittain ryhmitelty kalenterilistaus -->\n        <div id=\"kv-calendar-accordion-container\">\n            <p style=\"text-align: center;\">P\u00e4ivitet\u00e4\u00e4n kalenteria...<\/p>\n        <\/div>\n    <\/div>\n\n    <style>\n        :root {\n            --kv-primary: #0f172a;\n            --kv-accent: #e11d48;\n            --kv-border: #e2e8f0;\n            --kv-surface: #ffffff;\n        }\n        .kv-kalenteri-wrapper { max-width: 1000px; margin: 20px auto; font-family: system-ui, -apple-system, sans-serif; color: #334155; width: 100%; }\n        \n        .kv-tabs { display: flex; gap: 10px; margin-bottom: 20px; border-bottom: 2px solid var(--kv-border); padding-bottom: 10px; }\n        .kv-tab-btn { background: #f1f5f9; border: 1px solid var(--kv-border); padding: 10px 20px; font-size: 1rem; font-weight: bold; border-radius: 6px; cursor: pointer; transition: all 0.2s; color: #475569; }\n        .kv-tab-btn:hover { background: #e2e8f0; }\n        .kv-tab-btn.active { background: var(--kv-primary); color: white; border-color: var(--kv-primary); }\n\n        .kv-box-today { background: linear-gradient(135deg, var(--kv-primary), #1e293b); color: white; padding: 25px; border-radius: 12px; margin-bottom: 30px; box-shadow: 0 4px 6px -1px rgb(0 0 0 \/ 0.1); }\n        .kv-box-today h2 { color: #f1f5f9; font-size: 1.4rem; margin: 0 0 15px 0 !important; display: flex; align-items: center; gap: 10px; font-weight: bold; }\n        .kv-box-today h2::before { content: \"\ud83d\udd34\"; font-size: 0.9rem; animation: kvBlink 1.5s infinite; }\n        @keyframes kvBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }\n        \n        .kv-grid-today { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px; }\n        .kv-card-today { background: rgba(255, 255, 255, 0.1); padding: 15px; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.2); }\n        .kv-card-today .time { font-size: 1.8rem; font-weight: bold; color: #f8fafc; line-height: 1.1; }\n        .kv-card-today .track { font-size: 1.3rem; font-weight: bold; margin: 5px 0; color: white; }\n        \n        .kv-search-input { width: 100% !important; padding: 12px 20px !important; border-radius: 8px !important; border: 1px solid var(--kv-border) !important; font-size: 1rem !important; margin-bottom: 25px !important; background: var(--kv-surface) !important; outline: none; box-shadow: inset 0 1px 2px rgba(0,0,0,0.05); }\n        \n        .kv-accordion-section { margin-bottom: 10px; border: 1px solid var(--kv-border); border-radius: 8px; overflow: hidden; background: var(--kv-surface); }\n        .kv-accordion-header { background: #f8fafc; padding: 15px 20px; font-size: 1.1rem; font-weight: bold; color: var(--kv-primary); cursor: pointer; display: flex; justify-content: space-between; align-items: center; user-select: none; transition: background 0.2s; }\n        .kv-accordion-header:hover { background: #f1f5f9; }\n        .kv-accordion-icon { transition: transform 0.2s; font-size: 0.9rem; }\n        \n        .kv-accordion-content { display: none; padding: 15px; background: #ffffff; border-top: 1px solid var(--kv-border); flex-direction: column; gap: 10px; width: 100%; box-sizing: border-box; }\n        \n        .kv-accordion-section.open .kv-accordion-content { display: flex; }\n        .kv-accordion-section.open .kv-accordion-icon { transform: rotate(180deg); }\n        \n        \/* \ud83d\udda5\ufe0f P\u00f6yt\u00e4koneen sarakeleveydet lukittu tiukasti prosentteihin (Yhteens\u00e4 tasan 100%) *\/\n        .kv-table-headers { display: grid; grid-template-columns: 15% 10% 35% 30% 10%; gap: 10px; padding: 5px 20px; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; color: #64748b; letter-spacing: 0.05em; border-bottom: 1px solid var(--kv-border); padding-bottom: 10px; margin-bottom: 5px; }\n\n        .kv-row { background: var(--kv-surface); border: 1px solid var(--kv-border); padding: 14px 20px; border-radius: 6px; display: grid; grid-template-columns: 15% 10% 35% 30% 10%; align-items: center; gap: 10px; transition: transform 0.2s; box-sizing: border-box; width: 100%; }\n        .kv-row:hover { transform: translateY(-1px); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\n        \n        .kv-row .date { font-weight: 600; color: var(--kv-primary); }\n        .kv-row .time-cell { font-weight: bold; }\n        \n        \/* Korjaus: Sallitaan pitkien tekstien rivitty\u00e4 vapaasti ilman sarakkeen venymist\u00e4 sivulle *\/\n        .kv-row .track-cell { font-weight: bold; font-size: 1.05rem; color: var(--kv-primary); word-break: break-word; line-height: 1.3; padding-right: 5px; }\n        .kv-row .game-cell { font-size: 0.95rem; color: #334155; font-weight: 600; word-break: break-word; line-height: 1.3; }\n        \n        \/* Ratanumero pysyy tiukasti omalla paikallaan *\/\n        .kv-row .track-num-cell { font-size: 0.95rem; font-weight: bold; color: #64748b; text-align: center; }\n        \n        .kv-cancelled { background: #fee2e2 !important; border-color: #fca5a5 !important; opacity: 0.7; }\n        .kv-cancelled .time-cell, .kv-cancelled .track-cell, .kv-cancelled .game-cell, .kv-cancelled .track-num-cell { color: #ef4444 !important; text-decoration: line-through; }\n        .kv-none { text-align: center; padding: 30px; background: var(--kv-surface); border-radius: 8px; }\n        \n        \/* \ud83d\udcf1 Mobiilin\u00e4kym\u00e4 pysyy siistin\u00e4 listana *\/\n        @media (max-width: 768px) {\n            .kv-table-headers { display: none; }\n            .kv-row { grid-template-columns: 1fr !important; gap: 6px; padding: 12px; }\n            .kv-row .date, .kv-row .time-cell { display: inline-block; margin-right: 10px; }\n            .kv-row .track-cell { font-size: 1rem; margin: 4px 0; }\n            .kv-row .track-num-cell { text-align: left; font-size: 0.85rem; color: #64748b; margin-top: 2px; }\n            .kv-row .track-num-cell::before { content: \"Ratanumero: \"; font-weight: normal; }\n        }\n    <\/style>\n\n    <script>\n    (function() {\n        const countryEndpoints = {\n            suomi: 'https:\/\/docs.google.com\/spreadsheets\/d\/e\/2PACX-1vRH9m39yloYfniPj_fhWlc2DyTpRUyCzjymACs0Gt78adkukxJAxpS7StqJzmvXcKHaKUFa6X8EMZXn\/pub?output=csv',\n            ruotsi: '',\n            uk: ''\n        };\n\n        const monthNamesFi = [\n            \"Tammikuu\", \"Helmikuu\", \"Maaliskuu\", \"Huhtikuu\", \"Toukokuu\", \"Kes\u00e4kuu\",\n            \"Hein\u00e4kuu\", \"Elokuu\", \"Syyskuu\", \"Lokakuu\", \"Marraskuu\", \"Joulukuu\"\n        ];\n\n        let activeCountry = 'suomi';\n        if (!countryEndpoints.suomi) {\n            if (countryEndpoints.ruotsi) activeCountry = 'ruotsi';\n            else if (countryEndpoints.uk) activeCountry = 'uk';\n        }\n\n        let cacheStorage = {};\n\n        function getFormattedToday() {\n            const d = new Date();\n            return `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}.${d.getFullYear()}`;\n        }\n\n        function getCurrentMonthIndex() {\n            return new Date().getMonth();\n        }\n\n        function parseTabCSV(text) {\n            const lines = text.split('\\n').map(r => r.trim()).filter(r => r.length > 0);\n            if (lines.length <= 1) return [];\n\n            const items = [];\n            for(let i = 1; i < lines.length; i++) {\n                const cells = lines[i].match(\/(\".*?\"|[^\",\\s]+)(?=\\s*,|\\s*$)\/g) || lines[i].split(',');\n                if(cells.length < 3) continue;\n\n                const clean = cells.map(c => c.replace(\/^\"|\"$\/g, '').trim());\n                const rawDate = clean[0] || \"\";\n                const matchParts = rawDate.match(\/(\\d+)\\.(\\d+)\\.(\\d+)\/);\n                \n                let cleanKey = \"\";\n                let monthIdx = -1;\n                if(matchParts) {\n                    cleanKey = `${matchParts[1].padStart(2,'0')}.${matchParts[2].padStart(2,'0')}.${matchParts[3]}`;\n                    monthIdx = parseInt(matchParts[2], 10) - 1;\n                }\n\n                items.push({\n                    pvmDisplay: rawDate,\n                    pvmMatchKey: cleanKey,\n                    monthIndex: monthIdx,\n                    klo: clean[1] || \"\",\n                    rata: clean[2] || \"\",      \n                    tyyppi: clean[3] || \"\",    \n                    ratanro: clean[4] || \"\"    \n                });\n            }\n            return items;\n        }\n\n        window.toggleAccordion = function(headerElement) {\n            const parentSection = headerElement.parentElement;\n            parentSection.classList.toggle('open');\n        };\n\n        function renderActiveTab() {\n            const searchQuery = document.getElementById('kv-calendar-search').value.toLowerCase();\n            const data = cacheStorage[activeCountry] || [];\n            const todayStr = getFormattedToday();\n            const currentMonthIdx = getCurrentMonthIndex();\n\n            const labels = { suomi: 'Suomi', ruotsi: 'Ruotsi', uk: 'UK' };\n            document.getElementById('kv-today-title').innerText = `Ravit T\u00e4n\u00e4\u00e4n (${labels[activeCountry]})`;\n\n            \/\/ 1. P\u00e4iv\u00e4n l\u00e4ht\u00f6jen nostoalue\n            const todayMatches = data.filter(r => r.pvmMatchKey === todayStr && !r.klo.toUpperCase().includes('PERUTTU'));\n            const todayBox = document.getElementById('kv-today-container');\n            if(todayMatches.length === 0) {\n                todayBox.innerHTML = `<p>Ei virallisia ravil\u00e4ht\u00f6j\u00e4 merkitty t\u00e4lle p\u00e4iv\u00e4lle (${todayStr}).<\/p>`;\n            } else {\n                todayBox.innerHTML = todayMatches.map(r => `\n                    <div class=\"kv-card-today\">\n                        <div class=\"time\">Klo ${r.klo}<\/div>\n                        <div class=\"track\">${r.rata}<\/div>\n                        <div style=\"font-weight:bold; font-size:0.95rem; margin-top:5px; color:#e2e8f0;\">${r.tyyppi}<\/div>\n                    <\/div>\n                `).join('');\n            }\n\n            \/\/ 2. Hakuehdon suodatus\n            const filteredData = data.filter(r => \n                r.rata.toLowerCase().includes(searchQuery) || \n                r.tyyppi.toLowerCase().includes(searchQuery) || \n                r.pvmDisplay.toLowerCase().includes(searchQuery)\n            );\n\n            const accordionContainer = document.getElementById('kv-calendar-accordion-container');\n            if(filteredData.length === 0) {\n                accordionContainer.innerHTML = `<div class=\"kv-none\">Ei hakutuloksia t\u00e4st\u00e4 maasta.<\/div>`;\n                return;\n            }\n\n            const groupedMonths = {};\n            filteredData.forEach(r => {\n                if (r.monthIndex >= 0 && r.monthIndex <= 11) {\n                    if (!groupedMonths[r.monthIndex]) {\n                        groupedMonths[r.monthIndex] = [];\n                    }\n                    groupedMonths[r.monthIndex].push(r);\n                }\n            });\n\n            let htmlBuffer = \"\";\n            \n            for (let m = 0; m < 12; m++) {\n                if (!groupedMonths[m]) continue;\n\n                const shouldBeOpen = (m === currentMonthIdx) || (searchQuery.length > 0);\n                const sectionClass = shouldBeOpen ? 'kv-accordion-section open' : 'kv-accordion-section';\n                const countBadge = groupedMonths[m].length;\n\n                htmlBuffer += `\n                    <div class=\" ${sectionClass} \">\n                        <div class=\"kv-accordion-header\" onclick=\"toggleAccordion(this)\">\n                            <span>${monthNamesFi[m]} (${countBadge})<\/span>\n                            <span class=\"kv-accordion-icon\">\u25bc<\/span>\n                        <\/div>\n                        <div class=\"kv-accordion-content\">\n                            <div class=\"kv-table-headers\">\n                                <div>P\u00e4iv\u00e4m\u00e4\u00e4r\u00e4<\/div>\n                                <div>Aika<\/div>\n                                <div>Ravirata<\/div>\n                                <div>Pelikohde<\/div>\n                                <div style=\"text-align: center; width: 60px;\">Rata<\/div>\n                            <\/div>\n                            ${groupedMonths[m].map(r => {\n                                const isCancelled = r.klo.toUpperCase().includes('PERUTTU');\n                                const hasTrackNumber = r.ratanro && r.ratanro.trim() !== \"\" && r.ratanro.trim() !== \"0\";\n                                const trackValue = hasTrackNumber ? r.ratanro : '-';\n                                \n                                return `\n                                    <div class=\"kv-row\" style=\"${isCancelled ? 'background-color: #fee2e2 !important; border-color: #fca5a5 !important; opacity: 0.7;' : ''}\">\n                                        <div class=\"date\">${r.pvmDisplay}<\/div>\n                                        <div class=\"time-cell\">${r.klo}<\/div>\n                                        <div class=\"track-cell\">${r.rata}<\/div>\n                                        <div class=\"game-cell\">${r.tyyppi || '-'}<\/div>\n                                        <div class=\"track-num-cell\">${trackValue}<\/div>\n                                    <\/div>\n                                `;\n                            }).join('')}\n                        <\/div>\n                    <\/div>\n                `;\n            }\n\n            accordionContainer.innerHTML = htmlBuffer;\n        }\n\n        window.switchCountryTab = async function(countryKey) {\n            activeCountry = countryKey;\n            \n            document.querySelectorAll('.kv-tab-btn').forEach(btn => {\n                btn.classList.remove('active');\n                if(btn.getAttribute('data-country') === countryKey) {\n                    btn.classList.add('active');\n                }\n            });\n\n            document.getElementById('kv-calendar-accordion-container').innerHTML = `<p style=\"text-align: center;\">Ladataan maan tietoja...<\/p>`;\n\n            if (!cacheStorage[countryKey]) {\n                try {\n                    const res = await fetch(countryEndpoints[countryKey]);\n                    const csv = await res.text();\n                    cacheStorage[countryKey] = parseTabCSV(csv);\n                } catch (e) {\n                    console.error(e);\n                    document.getElementById('kv-calendar-accordion-container').innerHTML = `<div class=\"kv-none\" style=\"color:red;\">Virhe ladattaessa maan tietoja.<\/div>`;\n                    return;\n                }\n            }\n            renderActiveTab();\n        }\n\n        async function initKvCalendar() {\n            try {\n                const targetUrl = countryEndpoints[activeCountry];\n                if(!targetUrl) return;\n                \n                const res = await fetch(targetUrl);\n                const csv = await res.text();\n                cacheStorage[activeCountry] = parseTabCSV(csv);\n                renderActiveTab();\n                \n                document.getElementById('kv-calendar-search').addEventListener('input', renderActiveTab);\n            } catch(e) {\n                console.error(e);\n                document.getElementById('kv-calendar-accordion-container').innerHTML = `<div class=\"kv-none\" style=\"color:red;\">Virhe k\u00e4ynnistett\u00e4ess\u00e4 kalenteria.<\/div>`;\n            }\n        }\n\n        if (document.readyState === 'loading') {\n            document.addEventListener('DOMContentLoaded', initKvCalendar);\n        } else {\n            initKvCalendar();\n        }\n    })();\n    <\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-10","page","type-page","status-publish"],"_links":{"self":[{"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/pages\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10"}],"version-history":[{"count":2,"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/pages\/10\/revisions"}],"predecessor-version":[{"id":44,"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=\/wp\/v2\/pages\/10\/revisions\/44"}],"wp:attachment":[{"href":"https:\/\/totoveikkaus.fi\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}