{"id":147,"date":"2025-09-15T08:16:18","date_gmt":"2025-09-15T08:16:18","guid":{"rendered":"https:\/\/www.trolskaskogen.se\/?page_id=147"},"modified":"2026-01-24T11:55:59","modified_gmt":"2026-01-24T10:55:59","slug":"theater-tickets","status":"publish","type":"page","link":"https:\/\/www.trolskaskogen.se\/en\/theater-tickets\/","title":{"rendered":"Theater tickets"},"content":{"rendered":"<div data-block=\"subhero\"\n    class=\"acf-subhero flex items-center py-[84px] bg-greenFive  -mb-12\">\n    \n    <section class=\"container mx-auto px-6 md:px-8 flex  flex-col-reverse 2xl:flex-row 2xl:justify-between items-center gap-8\">\n        <div class=\"flex flex-col justify-center gap-5 max-w-[516px]\">\n            \n                                                <h1 class=\"heading-md text-greenOne\">\n                        Oh my, what a soup!<\/h1>\n                            \n                            <div class=\"body-lg max-w-3xl   text-black\">\n                    <p>This summer's new theater adventure \u201dDocksoppan\u201d is a furiously fun and exciting adventure for all generations. A magical experience that takes you through all the fairy tale environments of the forest. Running from June 21 to August 9, every day. Starts every half hour from 10:00 to 14:30. Limited number of places with a maximum of 80 people in each group. Very welcome!<\/p>\n<\/div>\n            \n                    <\/div>\n\n        <div class=\"flex justify-center 2xl:justify-end w-full\">\n                            <div class=\"relative w-full max-w-[880px] cloud-mask overflow-hidden h-[200px] md:h-[490px]\">\n                    <picture>\n                                                    <source media=\"(max-width: 767px)\" srcset=\"https:\/\/images.ohmyhosting.se\/WksCIwfUCQ1v6m9nZlde-Oja-8Q=\/fit-in\/390x300\/smart\/filters:quality(85)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Ftroll.png\">\n                                                                            <source media=\"(min-width: 768px)\" srcset=\"https:\/\/images.ohmyhosting.se\/aFdey8w5n-t9N4PbbYuca6haqVo=\/fit-in\/800x520\/smart\/filters:quality(90)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Ftroll.png\">\n                                                <img decoding=\"async\" src=\"https:\/\/www.trolskaskogen.se\/wp-content\/uploads\/2026\/01\/troll.png\" alt=\"\"\n                            class=\"absolute inset-0 w-full h-full object-cover object-center\" loading=\"lazy\">\n                    <\/picture>\n                <\/div>\n                    <\/div>\n    <\/section>\n<\/div>\n\n\n<div id=\"buy-ticket-module\" class=\"max-w-[800px]  xl:container mx-auto py-20 px-4 -mb-12\">\n    <div class=\"bg-chanterelleTwo relative h-full xl:h-[960px] rounded-lg overflow-hidden\">\n        <img decoding=\"async\" class=\"absolute right-0 object-cover h-full hidden xl:block z-10 rounded-lg\"\n             src=\"https:\/\/images.ohmyhosting.se\/bk_YzReX1BRz6-sX50EClZNqlHE=\/fit-in\/1233x960\/smart\/filters:quality(92)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Fbiljettbild-2026.jpg\"\n              srcset=\"https:\/\/images.ohmyhosting.se\/bk_YzReX1BRz6-sX50EClZNqlHE=\/fit-in\/1233x960\/smart\/filters:quality(92)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Fbiljettbild-2026.jpg\"              alt=\"ticket image 2026\" loading=\"lazy\">\n        <img decoding=\"async\" class=\"object-cover w-full xl:hidden\" src=\"https:\/\/images.ohmyhosting.se\/17zbA_ihjSiurrKHS1D_xWCfsCw=\/fit-in\/358x220\/smart\/filters:quality(92)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Fbiljettbild-2026.jpg\"\n              srcset=\"https:\/\/images.ohmyhosting.se\/17zbA_ihjSiurrKHS1D_xWCfsCw=\/fit-in\/358x220\/smart\/filters:quality(92)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2026%2F01%2Fbiljettbild-2026.jpg\"              alt=\"ticket image 2026\" loading=\"lazy\">\n        <div class=\"absolute top-0 -left-70 h-full z-20 pointer-events-none hidden xl:block w-[75%]\">\n            <div class=\"flex items-start justify-start h-full\">\n                <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewbox=\"0 0 643 660\"\n                     class=\"text-chanterelleTwo w-full h-full\">\n                    <path d=\"M560 660H0V0L560 0C670.617 210.032 670.617 449.968 560 660Z\" fill=\"currentColor\" \/>\n                <\/svg>\n            <\/div>\n        <\/div>\n        <div class=\"relative pb-20\">\n            <div class=\"absolute top-0 sm:-top-10 md:-top-16 -mt-[55px] mb-16 w-full z-20 pointer-events-none block xl:hidden\">\n                <svg class=\"text-chanterelleTwo w-full h-full\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\n                     viewbox=\"0 0 358 60\" fill=\"none\">\n                    <path d=\"M358 41.6023V60H0V41.6023C113.926 -13.8674 244.074 -13.8674 358 41.6023Z\"\n                          fill=\"currentColor\" \/>\n                <\/svg>\n            <\/div>\n            <div class=\"relative flex flex-col items-start md:w-[415px] pt-8 md:pt-20 md:ml-28 px-6 md:px-0 z-30 justify-center\">\n                <div class=\"max-w-3xl flex flex-col gap-3 mb-8\">\n                    <h2 class=\"text-peppery heading-lg\">\n                        Buy a ticket\n                    <\/h2>\n                    <h2 class=\"text-peppery body-md\">The gift card\/discount code is registered at the checkout.<\/h2>\n                <\/div>\n                \n                                <div id=\"person-names-translations\" style=\"position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;\" aria-hidden=\"true\">\n                                            <span data-original=\"Teaterbiljett (4-99 \u00e5r)\">Theater ticket (4-99 years)<\/span>\n                                            <span data-original=\"Barn 0-3 \u00e5r\">Children 0-3 years<\/span>\n                                            <span data-original=\"Ledsagare enligt LSS\">Companion according to LSS<\/span>\n                                    <\/div>\n                                    <div class=\"w-full mb-4\">\n                        <div class=\"relative\">\n                            <label for=\"product-selector\" class=\"block text-peppery font-excon font-medium mb-2\">\n                                Performance\n                            <\/label>\n                            <select\n                                id=\"product-selector\"\n                                name=\"product-selector\"\n                                class=\"js-show-select decorated appearance-none bg-white rounded-3xl px-4 py-2 focus:outline-none w-full md:w-[416px] text-black font-excon text-sm\"\n                            >\n                                                                    <option  value=\"3592\"  selected='selected'>\n                                        Sommar\u00e4ventyret Docksoppan\n                                    <\/option>\n                                                            <\/select>\n                            <div class=\"pointer-events-none absolute right-0 top-13 -translate-y-1\/2 flex items-center justify-center pr-3\">\n                                <svg class=\"h-4 w-4 text-black\"  viewbox=\"0 0 24 24\"  fill=\"none\"  stroke=\"currentColor\"  stroke-width=\"2\"  stroke-linecap=\"round\"  stroke-linejoin=\"round\">  <polyline points=\"6 9 12 15 18 9\" \/><\/svg>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                    <div id=\"booking-calendar-container\" class=\"w-full\">\n                        <div id=\"person-types-info\" class=\"mt-2 space-y-2\"><\/div>\n                        <div class=\"mb-4\">\n                            <label for=\"date-input\" class=\"block text-base font-excon mb-2 font-medium text-peppery\">\n                                Datum\n                            <\/label>\n                            <input id=\"date-input\" name=\"date-input\" type=\"text\"\n                                   class=\"kreng-datepicker decorated appearance-none bg-white rounded-3xl px-4 py-2 focus:outline-none w-full md:w-[416px] text-black text-sm font-excon\"\n                                   placeholder=\"V\u00e4lj datum\" autocomplete=\"off\" inputmode=\"none\">\n                        <\/div>\n                        <div class=\"mb-4\">\n                            <div class=\"relative\">\n                                <label for=\"time-selector\" class=\"block text-peppery font-excon font-medium mb-2\">\n                                    Tid\n                                <\/label>\n                                <select\n                                    id=\"time-selector\"\n                                    name=\"time-selector\"\n                                    class=\"decorated appearance-none bg-white rounded-3xl px-4 py-2 focus:outline-none w-full md:w-[416px] text-back text-sm font-excon\"\n                                >\n                                    <option value=\"\">Select date first<\/option>\n                                <\/select>\n                                <div class=\"pointer-events-none absolute right-0 top-13 -translate-y-1\/2 flex items-center justify-center pr-3\">\n                                    <svg class=\"h-4 w-4 text-black\"  viewbox=\"0 0 24 24\"  fill=\"none\"  stroke=\"currentColor\"  stroke-width=\"2\"  stroke-linecap=\"round\"  stroke-linejoin=\"round\">  <polyline points=\"6 9 12 15 18 9\" \/><\/svg>\n                                <\/div>\n                            <\/div>\n                        <\/div>\n                        <div id=\"total-price-box\" class=\"mt-6 text-lg font-semibold font-excon text-peppery\"><\/div>\n                        <button\n                            id=\"add-to-cart-btn\"\n                            type=\"button\"\n                            class=\"btn-green-rounded inline-flex mt-4 disabled:opacity-50 disabled:cursor-not-allowed\"\n                            disabled\n aria-disabled=\"true\"\n                        >\n                            <span class=\"btn-label\">L\u00e4gg i varukorg<\/span>\n                            <span class=\"spinner hidden ml-2 w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin\"><\/span>\n                        <\/button>\n                    <\/div>\n                                        <script nonce=\"jFMNOR+dGA1bPH02zkL78PQHUIU=\">\n                        window.krengCurrency = { current: \"SEK\",rates: []};\n                        window.trp_language = 'en_US';\n                        window.krengTranslations = {\n                            selectDateFirst: \"V\\u00e4lj datum f\\u00f6rst\",\n                            noTimesAvailable: \"Inga tider tillg\\u00e4ngliga\",\n                            selectTime: \"V\\u00e4lj tid\",\n                            available: \"Lediga\",\n                            fullyBooked: \"Fullbokad\",\n                            totalPrice: \"Totalpris\",\n                            adding: \"L\\u00e4gger till...\",\n                            addToCart: \"L\\u00e4gg i varukorg\",\n                            failedToAddToCart: \"Misslyckades att l\\u00e4gga i varukorg\",\n                            productAddedToCart: \"Produkt lagd i varukorgen\",\n                            technicalError: \"Tekniskt fel vid varukorg\",\n                            cartVerificationFailed: \"Produkten kunde inte sparas i varukorgen. F\\u00f6rs\\u00f6k igen.\"                        };\n                        \/\/ Build person names translation map from DOM (TranslatePress will translate the hidden div)\n                        window.krengPersonNamesTranslations = {};\n                        (function(){\n                            const container = document.getElementById('person-names-translations');\n                            if (container) {\n                                container.querySelectorAll('span[data-original]').forEach(span => {\n                                    const original = span.getAttribute('data-original');\n                                    const translated = span.textContent;\n                                    if (original && translated) {\n                                        window.krengPersonNamesTranslations[original] = translated;\n                                    }\n                                });\n                            }\n                        })();\n                        (function(){\n                            if (window.location.hash !== '#buy-ticket-module') {\n                                return;\n                            }\n\n                            window.addEventListener('load', () => {\n                                window.setTimeout(() => {\n                                    const target = document.getElementById('buy-ticket-module');\n\n                                    if (target) {\n                                        target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n                                    }\n                                }, 150);\n                            }, { once: true });\n                        })();\n                        (function(){\n                            const qs = id => document.getElementById(id)\n                            const productSelector = qs('product-selector')\n                            const dateInput = qs('date-input')\n                            const timeSelector = qs('time-selector')\n                            const personTypesBox = qs('person-types-info')\n                            const totalPriceBox = qs('total-price-box')\n                            const addToCartBtn = qs('add-to-cart-btn')\n                            let picker = null\n                            let availabilityData = {}\n                            let enabledDates = []\n                            let personTypesData = []\n                            let currentProduct = null\n                            let availabilityReqId = 0\n                            let cartReadyPromise = null\n                            const currencyFormat = v => {\n                                const cur = 'SEK';\n                                const rates = window.krengCurrency?.rates || { SEK: 1 };\n                                const rate = rates[cur] || 1;\n                                let value = v * rate;\n                                const locale = 'sv-SE';\n                                let opts = { style: 'currency', currency: cur };\n                                try { return value.toLocaleString(locale, opts); }\n                                catch (e) { return value + ' kr'; }\n                            }\n                            const clamp = (val,min,max) => Math.min(Math.max(val,min),max)\n                            function initFlatpickr(){\n                                if (!window.flatpickr || !dateInput) return\n                                if (dateInput._flatpickr) dateInput._flatpickr.destroy()\n                                picker = flatpickr(dateInput,{\n                                    dateFormat:'Y-m-d',\n                                    locale:'sv',\n                                    enable: enabledDates,\n                                    disableMobile:true,\n                                    onChange: ([d],str)=>{ if(str){ renderTimes(str); autoSelectSingleTime(); validateForm() } }\n                                })\n                            }\n                            function ensureFlatpickrReady(cb){\n                                if (window.flatpickr) return cb()\n                                const start = Date.now()\n                                const int = setInterval(()=>{\n                                    if (window.flatpickr){ clearInterval(int); cb() }\n                                    else if (Date.now()-start>5000){ clearInterval(int) }\n                                },40)\n                            }\n                            function applyEnabledDates(){\n                                if (!picker) return\n                                picker.set('enable', enabledDates)\n                                if (enabledDates.length){\n                                    const cur = picker.input.value\n                                    if (!cur || !enabledDates.includes(cur)){\n                                        picker.setDate(enabledDates[0],true)\n                                    } else {\n                                        renderTimes(cur)\n                                    }\n                                } else {\n                                    picker.clear()\n                                    resetTimesForNoDate()\n                                }\n                                validateForm()\n                            }\n                            function resetTimesForNoDate(){\n                                timeSelector.innerHTML = '<option value=\"\">' + (window.krengTranslations?.selectDateFirst || 'V\u00e4lj datum f\u00f6rst') + '<\/option>'\n                            }\n                            function renderTimes(date){\n                                timeSelector.innerHTML = ''\n                                const list = availabilityData[date] || []\n                                if (!list.length){\n                                    timeSelector.innerHTML = '<option value=\"\">' + (window.krengTranslations?.noTimesAvailable || 'Inga tider tillg\u00e4ngliga') + '<\/option>'\n                                    return\n                                }\n                                const def = document.createElement('option')\n                                def.value=''\n                                def.textContent = window.krengTranslations?.selectTime || 'V\u00e4lj tid'\n                                timeSelector.appendChild(def)\n                                list.forEach(slot=>{\n                                    const o = document.createElement('option')\n                                    const remaining = (slot.remaining ?? null)\n                                    const availableText = window.krengTranslations?.available || 'Lediga'\n                                    const fullyBookedText = window.krengTranslations?.fullyBooked || 'Fullbokad'\n                                    const labelRemaining = remaining === null ? '' : (remaining > 0 ? ' (' + availableText + ': '+remaining+')' : ' (' + fullyBookedText + ')')\n                                    o.value = slot.slot\n                                    \/\/ Use display_time if available, otherwise extract start time from slot\n                                    const displayTime = slot.display_time || (slot.slot.includes(' - ') ? slot.slot.split(' - ')[0].trim() : slot.slot)\n                                    o.textContent = displayTime + labelRemaining\n                                    if (slot.available === false || remaining === 0) o.disabled = true\n                                    timeSelector.appendChild(o)\n                                })\n                            }\n                            function autoSelectSingleTime(){\n                                const opts = [...timeSelector.options].filter(o=>o.value)\n                                if (opts.length === 1 && !timeSelector.value && !opts[0].disabled){\n                                    timeSelector.value = opts[0].value\n                                }\n                            }\n                            async function fetchJSON(url, signal){\n                                const timeout = new Promise((_,rej)=>setTimeout(()=>rej(new Error('timeout')),7000))\n                                const res = await Promise.race([fetch(url,{credentials:'include',signal}), timeout])\n                                if (!res.ok) throw new Error('HTTP '+res.status)\n                                return res.json()\n                            }\n                            async function fetchAvailability(productId){\n                                if (!productId) return\n                                const reqId = ++availabilityReqId\n                                currentProduct = productId\n                                availabilityData = {}\n                                enabledDates = []\n                                resetTimesForNoDate()\n                                if (picker) picker.clear()\n                                validateForm()\n                                try {\n                                    const data = await fetchJSON(`\/wp-json\/kreng\/v1\/availability?product_id=${encodeURIComponent(productId)}`)\n                                    if (reqId !== availabilityReqId) return\n                                    availabilityData = data || {}\n                                    enabledDates = Object.keys(availabilityData)\n                                    applyEnabledDates()\n                                } catch(e){\n                                    availabilityData = {}\n                                    enabledDates = []\n                                    applyEnabledDates()\n                                }\n                            }\n                            function renderPersonTypes(data){\n                                if (!data || !data.enabled || !Array.isArray(data.types) || !data.types.length){\n                                    personTypesData = []\n                                    personTypesBox.innerHTML = ''\n                                    updateTotalPrice()\n                                    validateForm()\n                                    return\n                                }\n                                personTypesData = data.types\n                                personTypesBox.innerHTML = `<form id=\"person-types-form\" class=\"space-y-3 mb-4\">${\n                                    data.types.map(t=>{\n                                        const priceVal = (t.cost || t.base_cost || 0)\n                                        const priceLabel = currencyFormat(priceVal)\n                                        \/\/ Get translated name from mapping, fallback to original\n                                        const translatedName = window.krengPersonNamesTranslations[t.name] || t.name\n                                        return `\n                                            <div class=\"person-type-row flex items-center justify-between font-excon\">\n                                                <label class=\"text-base font-medium text-peppery\" for=\"person-type-${t.id}\">\n                                                    ${translatedName} <span class=\"text-peppery font-normal\">(${priceLabel})<\/span>\n                                                <\/label>\n                                                <div class=\"quantity-selector flex flex-col items-start gap-2 mt-0\">\n                                                    <div class=\"flex items-center justify-center md:w-[94px] p-0 md:bg-white rounded-full\">\n                                                        <button type=\"button\"\n                                                            class=\"qty-btn quantity-decrease max-md:bg-greenTwo text-white block md:w-6 w-11 rounded-full h-11 m-0 no-underline text-center leading-10 md:text-[#8F9496] text-lg font-bold cursor-pointer\"\n                                                            data-target=\"person-type-${t.id}\" data-delta=\"-1\" aria-label=\"Minska ${translatedName}\">\u2013<\/button>\n                                                        <input\n                                                            type=\"number\"\n                                                            inputmode=\"numeric\"\n                                                            pattern=\"[0-9]*\"\n                                                            id=\"person-type-${t.id}\"\n                                                            name=\"person-type-${t.id}\"\n                                                            min=\"0\"\n                                                            max=\"${t.max ?? 99}\"\n                                                            value=\"0\"\n                                                            aria-label=\"${translatedName}\"\n                                                            class=\"quantity-input md:bg-white bg-chanterelleTwo h-11 w-8 md:mx-0 mx-2 text-center text-md\"\n                                                            ${t.max === 0 ? 'disabled' : ''}\n                                                        \/>\n                                                        <button type=\"button\"\n                                                            class=\"qty-btn quantity-increase block md:w-6 w-11 h-11 m-0 no-underline text-center leading-10 md:text-[#8F9496] text-lg rounded-full max-md:bg-greenTwo text-white font-bold cursor-pointer\"\n                                                            data-target=\"person-type-${t.id}\" data-delta=\"1\" aria-label=\"\u00d6ka ${translatedName}\">+<\/button>\n                                                    <\/div>\n                                                <\/div>\n                                            <\/div>\n                                        `\n                                    }).join('')\n                                }<\/form>`\n                                const form = document.getElementById('person-types-form')\n                                if (form){\n                                    form.querySelectorAll('input.quantity-input').forEach(inp=>{\n                                        inp.addEventListener('input', e=>{\n                                            const max = parseInt(e.target.getAttribute('max'),10) || 999\n                                            const min = parseInt(e.target.getAttribute('min'),10) || 0\n                                            const v = parseInt(e.target.value,10)\n                                            e.target.value = isNaN(v)?0:clamp(v,min,max)\n                                            updateTotalPrice()\n                                            validateForm()\n                                        })\n                                    })\n                                }\n                                updateTotalPrice()\n                                validateForm()\n                            }\n                            async function fetchPersonTypes(productId){\n                                if (!productId){ renderPersonTypes(null); return }\n                                try {\n                                    const data = await fetchJSON(`\/wp-json\/kreng\/v1\/person-types?product_id=${encodeURIComponent(productId)}`)\n                                    renderPersonTypes(data)\n                                } catch(e){\n                                    renderPersonTypes(null)\n                                }\n                            }\n                            function getSelectedPersons(){\n                                const form = document.getElementById('person-types-form')\n                                if (!form || !personTypesData.length) return []\n                                const out = []\n                                personTypesData.forEach(t=>{\n                                    const el = form.querySelector(`#person-type-${t.id}`)\n                                    if (!el || el.disabled) return\n                                    const qty = parseInt(el.value,10)||0\n                                    if (qty>0) out.push({id:t.id, qty})\n                                })\n                                return out\n                            }\n                            function updateTotalPrice(){\n                                if (!totalPriceBox) return\n                                const persons = getSelectedPersons()\n                                let total = 0\n                                persons.forEach(p=>{\n                                    const meta = personTypesData.find(t=>t.id === p.id)\n                                    if (meta) total += p.qty * (meta.cost || meta.base_cost || 0)\n                                })\n                                const totalPriceText = window.krengTranslations?.totalPrice || 'Totalpris'\n                                totalPriceBox.textContent = `${totalPriceText}: ${currencyFormat(total)}`\n                            }\n                            function timeIsValid(){\n                                const d = dateInput.value\n                                const t = timeSelector.value\n                                if (!d || !t) return false\n                                const list = availabilityData[d] || []\n                                return list.some(s=>s.slot===t && s.available !== false && (s.remaining === null || s.remaining > 0))\n                            }\n                            function validateForm(){\n                                const valid = !!(productSelector.value && dateInput.value && timeSelector.value && timeIsValid() && getSelectedPersons().length)\n                                addToCartBtn.disabled = !valid\n                                addToCartBtn.setAttribute('aria-disabled', addToCartBtn.disabled ? 'true':'false')\n                                return valid\n                            }\n                            function setLoading(loading){\n                                const spinner = addToCartBtn.querySelector('.spinner')\n                                const label = addToCartBtn.querySelector('.btn-label')\n                                const addingText = window.krengTranslations?.adding || 'L\u00e4gger till...'\n                                const addToCartText = window.krengTranslations?.addToCart || 'L\u00e4gg i varukorg'\n                                if (label) label.textContent = loading ? addingText : addToCartText\n                                if (spinner){\n                                    if (loading){ spinner.classList.remove('hidden'); spinner.classList.add('inline-block') }\n                                    else { spinner.classList.add('hidden'); spinner.classList.remove('inline-block') }\n                                }\n                                addToCartBtn.disabled = loading || !validateForm()\n                                addToCartBtn.setAttribute('aria-disabled', addToCartBtn.disabled ? 'true':'false')\n                                const disable = el => { if (el) el.toggleAttribute('data-disabled-original', loading); el && (el.disabled = loading) }\n                                ;[productSelector,dateInput,timeSelector].forEach(disable)\n                                const form = document.getElementById('person-types-form')\n                                if (form){\n                                    form.querySelectorAll('input,select,button').forEach(i=> i.disabled = loading)\n                                }\n                            }\n                            function clearForm(){\n                                const form = document.getElementById('person-types-form')\n                                if (form){\n                                    form.querySelectorAll('input[type=\"number\"]').forEach(i=> i.value = 0)\n                                }\n                                if (picker) picker.clear()\n                                resetTimesForNoDate()\n                                updateTotalPrice()\n                                validateForm()\n                            }\n                            function notify(msg,type='success'){\n                                const ev = new CustomEvent('kreng:notify',{detail:{message:msg,type}})\n                                document.dispatchEvent(ev)\n                                if (!window?.krengNotifyHandled) console.log(msg)\n                            }\n                            async function addToCartRequest(payload){\n                                const res = await fetch('\/wp-json\/kreng\/v1\/add-show-to-cart',{\n                                    method:'POST',\n                                    headers:{'Content-Type':'application\/json'},\n                                    body: JSON.stringify(payload),\n                                    credentials:'include'\n                                })\n                                const data = await res.json().catch(()=>null)\n                                return {res, data}\n                            }\n                            addToCartBtn.addEventListener('click', async function(){\n                                if (addToCartBtn.disabled) return\n                                if (!validateForm()) return\n                                const productId = parseInt(productSelector.value,10)\n                                const selectedDate = dateInput.value\n                                const selectedTime = timeSelector.value\n                                if (!timeIsValid()) return\n                                const persons = getSelectedPersons()\n                                if (!persons.length) return\n                                const payload = { product_id: productId, date: selectedDate, time: selectedTime, persons }\n                                setLoading(true)\n                                try {\n                                    const {res, data} = await addToCartRequest(payload)\n                                    if (!res.ok || !data || data.error){\n                                        notify(window.krengTranslations?.failedToAddToCart || 'Misslyckades att l\u00e4gga i varukorg','error')\n                                    } else {\n                                        document.dispatchEvent(new CustomEvent('kreng:added-to-cart',{detail:data}))\n                                        document.dispatchEvent(new CustomEvent('kreng:cart-updated',{detail:data}))\n                                        clearForm()\n                                        notify(window.krengTranslations?.productAddedToCart || 'Produkt lagd i varukorgen','success')\n                                    }\n                                } catch(e){\n                                    notify(window.krengTranslations?.technicalError || 'Tekniskt fel vid varukorg','error')\n                                } finally {\n                                    setLoading(false)\n                                }\n                            })\n                            productSelector.addEventListener('change', e=>{\n                                fetchAvailability(e.target.value)\n                                fetchPersonTypes(e.target.value)\n                            })\n                            timeSelector.addEventListener('change', ()=>{ validateForm() })\n                            document.addEventListener('input', e=>{\n                                if (e.target && e.target.closest('#person-types-form')) validateForm()\n                            })\n                            ensureFlatpickrReady(()=>{\n                                initFlatpickr()\n                                if (productSelector.value){\n                                    fetchAvailability(productSelector.value)\n                                    fetchPersonTypes(productSelector.value)\n                                }\n                            })\n                            \/\/ Delegated handler for + \/ - buttons (added)\n                            document.addEventListener('click', e=>{\n                                const btn = e.target.closest('.qty-btn')\n                                if (!btn) return\n                                const targetId = btn.getAttribute('data-target')\n                                const delta = parseInt(btn.getAttribute('data-delta'),10) || 0\n                                const input = targetId && document.getElementById(targetId)\n                                if (!input || input.disabled) return\n                                const max = parseInt(input.getAttribute('max'),10) || 999\n                                const min = parseInt(input.getAttribute('min'),10) || 0\n                                const cur = parseInt(input.value,10) || 0\n                                const next = clamp(cur + delta, min, max)\n                                if (next !== cur){\n                                    input.value = next\n                                    input.dispatchEvent(new Event('input', {bubbles:true}))\n                                }\n                            })\n                        })()\n                    <\/script>\n                            <\/div>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n<div data-block=\"text-and-image\"\n    class=\"acf-text-and-image bg-white  mb-0\">\n    <div\n        class=\"lg:grid lg:grid-cols-2 flex flex-col-reverse lg:flex-row max-w-[1440px] mx-auto py-24 px-4 md:px-8 text-lg gap-y-8 items-center gap-x-28 justify-items-center\">\n        \n                                    <div class=\"relative overflow-hidden rounded-2xl max-h-[880px] h-full md:order-2\">\n                    \n                    <img decoding=\"async\" src=\"https:\/\/images.ohmyhosting.se\/L-wTGE1_J3pxW-XUABTNIOqGJ4U=\/fit-in\/1220x740\/smart\/filters:quality(90)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F10%2Ftrollhus2.png\" alt=\"\"\n                        class=\"w-full lg:max-w-[582px] h-full max-w-[600px] object-contain object-center\" loading=\"lazy\" \/>\n                <\/div>\n                            \n        <div class=\"flex flex-col gap-3 justify-center max-w-[512px] md:order-1\">\n            \n                                                            <h2\n                        class=\"heading-md md:!text-[28px] font-bold leading-[110%] text-greenTwo\">\n                        BOOKING RULES\n                    <\/h2>\n                            \n                            <div class=\"wysiwyg wysiwyg-text text-black mb-2 max-w-[426px] break-normal\">\n                    <p>Purchased tickets can be transferred a maximum of two times, subject to availability, but are non-refundable.<\/p>\n<p>To move tickets:<br \/>\nemail info@trolskaskogen.se at least 24 hours before the visit is due to take place. Tickets cannot be transferred on the spot at the entrance.<\/p>\n\n                <\/div>\n            \n                    <\/div>\n    <\/div>\n<\/div>\n\n\n<div data-block=\"text-and-image\"\n    class=\"acf-text-and-image bg-greenFive  -mb-12\">\n    <div\n        class=\"lg:grid lg:grid-cols-2 flex flex-col-reverse lg:flex-row max-w-[1440px] mx-auto py-24 px-4 md:px-8 text-lg gap-y-8 items-center gap-x-28 justify-items-center\">\n        \n                                    <div class=\"relative overflow-hidden rounded-2xl max-h-[880px] h-full md:order-1\">\n                    \n                    <img decoding=\"async\" src=\"https:\/\/images.ohmyhosting.se\/J_a2CVu0h6AMhUP85DbuzQGpXx4=\/fit-in\/1220x740\/smart\/filters:quality(90)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F09%2F7col.png\" alt=\"\"\n                        class=\"w-full lg:max-w-[582px] h-full max-w-[600px] object-contain object-center\" loading=\"lazy\" \/>\n                <\/div>\n                            \n        <div class=\"flex flex-col gap-3 justify-center max-w-[512px] md:order-2\">\n            \n                                                            <h2\n                        class=\"heading-md md:!text-[28px] font-bold leading-[110%] text-greenOne\">\n                        Practical information for theatergoers\n                    <\/h2>\n                            \n                            <div class=\"wysiwyg wysiwyg-text text-black mb-2 max-w-[426px] break-normal\">\n                    <p>Audience groups with limited numbers start every 30 minutes between 10:00 - 14:30.<\/p>\n<p><strong>Please note!<\/strong>\u00a0The adventure starts at the time of your choice, so check in at the entrance a little before the start.<\/p>\n<p>The sago adventure in Trolska Skogen takes place after a distance of about 1.2 km. The whole walk takes between 1.5-2 hours.<br \/>\nVisitors start at the pre-booked time and then stop at the various fairytale locations where part of the story is played out. Our entrance hosts will show you the way to the start and guide the groups to the next station.<br \/>\nThe performance is divided into five different scenes that are between 8-14 minutes long.<\/p>\n\n                <\/div>\n            \n                            <a href=\"\/en\/plan\/practical-information\/\" target=\"\"\n                    class=\"btn-green-rounded inline-flex w-fit\">\n                    Get all the info here\n                <\/a>\n                    <\/div>\n    <\/div>\n<\/div>\n\n\n<div data-block=\"seperator\"\n    class=\"w-full   mb-0\"\n     style=\"background-color: #cceba5;\" >\n        <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"100%\" height=\"100%\" viewbox=\"0 0 1440 140\" fill=\"none\" preserveaspectratio=\"none\" class=\"max-h-[140px] -mb-0.5\">\n            <path\n                d=\"M1440 140H-0.000488281L0.0205078 1.15694H18.3705C24.3405 1.15694 31.7105 1.15694 40.3705 1.16684C132.74 -2.37521 222.61 2.20571 312.82 14.1082C325.71 15.8099 338.6 17.6601 351.49 19.6983C402.71 28.7315 448.71 54.4559 497.71 70.2863C552.71 87.1061 607.71 63.3605 663.71 55.4453C686.71 52.4771 709.71 49.5089 732.45 53.4269C745.41 55.475 758.051 58.6311 770.601 62.5195C795.701 70.2863 820.45 80.9223 844.7 95.0213C858.2 102.936 874.201 108.873 889.821 109.615C905.441 110.357 920.7 105.905 932.7 93.0425C971.7 40.6043 1036.7 19.8269 1101.7 26.7527C1136.7 31.6997 1169.7 37.6361 1204.7 31.6997C1267.7 19.8269 1324.7 -1.93988 1387.7 1.19652C1398.83 1.15694 1408.36 1.15694 1416.11 1.15694H1440L1439.98 140H1440Z\"\n                fill=\"#e3f7cf\" \/>\n        <\/svg>\n        <\/div>\n\n\n<div data-block=\"three-column-card\" class=\"acf-three-column-card bg-greenSix py-[144px] mb-0\">\n    <div class=\"container mx-auto max-w-[1240px] px-4\">\n                    <h2 class=\"heading-lg text-greenTwo text-center mb-10 max-w-5xl mx-auto\">Plan your visit<\/h2>\n        \n                    <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 justify-center items-stretch\">\n                                    <article class=\"bg-white rounded-[10px] overflow-hidden shadow-lg w-full flex flex-col p-6\">\n                                                    <div class=\"w-full h-[200px] overflow-hidden rounded-sm mb-4\">\n                                <img\n                                    src=\"https:\/\/images.ohmyhosting.se\/P33yGWmtI-dGEOEhClFS0SKSzwE=\/352x220\/smart\/filters:quality(85)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F09%2F8.col_.png\"\n                                    alt=\"8.col_\"\n                                    loading=\"lazy\"\n                                    decoding=\"async\"\n                                    class=\"w-full h-full object-cover\"\n                                >\n                            <\/div>\n                        \n                        <div class=\"flex-1 flex flex-col\">\n                                                            <h3 class=\"font-pally text-lg font-bold text-greenTwo mb-3\">Food and drink<\/h3>\n                            \n                                                            <div class=\"body-sm text-black font-excon mb-5 flex-1\"><p>In Trolska Skogen you can enjoy a variety of food and drink to suit all tastes. From delicious dishes inspired by nature to quicker options for those on the go, there is something for everyone to discover and enjoy<\/p>\n<\/div>\n                            \n                                                            <a href=\"\/en\/food-and-drink\/\"                                    class=\"inline-flex btn-green-rounded self-start mt-auto\">\n                                    Read more\n                                <\/a>\n                                                    <\/div>\n                    <\/article>\n                                    <article class=\"bg-white rounded-[10px] overflow-hidden shadow-lg w-full flex flex-col p-6\">\n                                                    <div class=\"w-full h-[200px] overflow-hidden rounded-sm mb-4\">\n                                <img\n                                    src=\"https:\/\/images.ohmyhosting.se\/GxAYFcNeEQEYT7RE_EyAkroc5VA=\/352x220\/smart\/filters:quality(85)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F09%2F9.col_.png\"\n                                    alt=\"9.col_\"\n                                    loading=\"lazy\"\n                                    decoding=\"async\"\n                                    class=\"w-full h-full object-cover\"\n                                >\n                            <\/div>\n                        \n                        <div class=\"flex-1 flex flex-col\">\n                                                            <h3 class=\"font-pally text-lg font-bold text-greenTwo mb-3\">Accommodation<\/h3>\n                            \n                                                            <div class=\"body-sm text-black font-excon mb-5 flex-1\"><p> The surrounding area offers a wide range of accommodation options. You can choose from charming cottages and vacation homes for a close contact with nature, comfortable hotels with facilities such as restaurants and spas, or campsites for a more adventurous stay.<\/p>\n<\/div>\n                            \n                                                            <a href=\"\/en\/accommodation\/\"                                    class=\"inline-flex btn-green-rounded self-start mt-auto\">\n                                    Read more\n                                <\/a>\n                                                    <\/div>\n                    <\/article>\n                                    <article class=\"bg-white rounded-[10px] overflow-hidden shadow-lg w-full flex flex-col p-6\">\n                                                    <div class=\"w-full h-[200px] overflow-hidden rounded-sm mb-4\">\n                                <img\n                                    src=\"https:\/\/images.ohmyhosting.se\/4GUeBES_Tt88BSHN34acr-cH3_w=\/352x220\/smart\/filters:quality(85)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F09%2F10.col_.png\"\n                                    alt=\"10.col_\"\n                                    loading=\"lazy\"\n                                    decoding=\"async\"\n                                    class=\"w-full h-full object-cover\"\n                                >\n                            <\/div>\n                        \n                        <div class=\"flex-1 flex flex-col\">\n                                                            <h3 class=\"font-pally text-lg font-bold text-greenTwo mb-3\">Intermediate fjord<\/h3>\n                            \n                                                            <div class=\"body-sm text-black font-excon mb-5 flex-1\"><p>Mellanfj\u00e4rden is a peaceful place with a beautiful bay and surrounding nature. Here you can enjoy the tranquillity, take a refreshing swim and explore the surrounding forest trails. It's a perfect place to relax and get closer to nature.<\/p>\n<\/div>\n                            \n                                                            <a href=\"https:\/\/www.trolskaskogen.se\/en\/the-middle-ground\/\"                                    class=\"inline-flex btn-green-rounded self-start mt-auto\">\n                                    Read more\n                                <\/a>\n                                                    <\/div>\n                    <\/article>\n                            <\/div>\n            <\/div>\n<\/div>\n\n\n<div data-block=\"seperator\"\n    class=\"w-full  rotate-180 mb-0\"\n     style=\"background-color: #ffffff;\" >\n        <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"100%\" height=\"100%\" viewbox=\"0 0 1440 140\" fill=\"none\" preserveaspectratio=\"none\" class=\"max-h-[140px] -mb-0.5\">\n            <path\n                d=\"M1440 140H-0.000488281L0.0205078 1.15694H18.3705C24.3405 1.15694 31.7105 1.15694 40.3705 1.16684C132.74 -2.37521 222.61 2.20571 312.82 14.1082C325.71 15.8099 338.6 17.6601 351.49 19.6983C402.71 28.7315 448.71 54.4559 497.71 70.2863C552.71 87.1061 607.71 63.3605 663.71 55.4453C686.71 52.4771 709.71 49.5089 732.45 53.4269C745.41 55.475 758.051 58.6311 770.601 62.5195C795.701 70.2863 820.45 80.9223 844.7 95.0213C858.2 102.936 874.201 108.873 889.821 109.615C905.441 110.357 920.7 105.905 932.7 93.0425C971.7 40.6043 1036.7 19.8269 1101.7 26.7527C1136.7 31.6997 1169.7 37.6361 1204.7 31.6997C1267.7 19.8269 1324.7 -1.93988 1387.7 1.19652C1398.83 1.15694 1408.36 1.15694 1416.11 1.15694H1440L1439.98 140H1440Z\"\n                fill=\"#e3f7cf\" \/>\n        <\/svg>\n        <\/div>\n\n\n<div data-block=\"text-and-image\"\n    class=\"acf-text-and-image bg-white  mb-16 md:mb-24\">\n    <div\n        class=\"lg:grid lg:grid-cols-2 flex flex-col-reverse lg:flex-row max-w-[1440px] mx-auto py-24 px-4 md:px-8 text-lg gap-y-8 items-center gap-x-28 justify-items-center\">\n        \n                                    <div class=\"relative overflow-hidden rounded-2xl max-h-[880px] h-full md:order-1\">\n                    \n                    <img decoding=\"async\" src=\"https:\/\/images.ohmyhosting.se\/xAmHFcVG2OXZMCnZddGSrxDOmj8=\/fit-in\/1220x740\/smart\/filters:quality(90)\/https%3A%2F%2Fwww.trolskaskogen.se%2Fwp-content%2Fuploads%2F2025%2F09%2F11col.png\" alt=\"\"\n                        class=\"w-full lg:max-w-[582px] h-full max-w-[600px] object-contain object-center\" loading=\"lazy\" \/>\n                <\/div>\n                            \n        <div class=\"flex flex-col gap-3 justify-center max-w-[512px] md:order-2\">\n            \n                                                            <h2\n                        class=\"heading-md md:!text-[28px] font-bold leading-[110%] text-greenTwo\">\n                        About us\n                    <\/h2>\n                            \n                            <div class=\"wysiwyg wysiwyg-text text-black mb-2 max-w-[426px] break-normal\">\n                    <p>At Trolska Skogen, we want to inspire people to keep their curiosity alive and discover the magic that surrounds us. By combining theater, music and nature, we create a playful world of adventure.<\/p>\n\n                <\/div>\n            \n                            <a href=\"https:\/\/www.trolskaskogen.se\/en\/about-us\/\" target=\"\"\n                    class=\"btn-green-rounded inline-flex w-fit\">\n                    Read more about us\n                <\/a>\n                    <\/div>\n    <\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-147","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/pages\/147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/comments?post=147"}],"version-history":[{"count":46,"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/pages\/147\/revisions"}],"predecessor-version":[{"id":3599,"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/pages\/147\/revisions\/3599"}],"wp:attachment":[{"href":"https:\/\/www.trolskaskogen.se\/en\/wp-json\/wp\/v2\/media?parent=147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}