PageSourceSearch

https://www.sipoonsanomat.fi/asenna/

html sipoonsanomat.fi collected 2026-10-02 12:14:55 UTC 110,593 bytes, 2,077 lines download raw bytes

1
2<!doctype html>
3<html class="diks-no-js diks-site--sipoonsanomat diks-user--is-not-logged-in diks-user--is-not-subscriber diks-user--is-not-company-subscriber diks-site--layout-master diks-site--ads-disabled-from-page-level" lang="fi" prefix="og: http://ogp.me/ns#">
4	<head>
5		<meta charset="utf-8">
6		<meta name="viewport" content="width=device-width, initial-scale=1">
7		<title>Sovellus | Sipoon Sanomat</title>
8		<link id="diks-stylesheet" rel="stylesheet" href="https://a.sipoonsanomat.fi/styles/2efe7af9/styles/diks-news.css">
9		<link rel="dns-prefetch" href="https://cdn.gravito.net">
10			<link rel="dns-prefetch" href="https://cdn.gravito.network">
11			<link rel="dns-prefetch" href="https://handshake.gravito.network">
12		
12<script>
13
14		const checkUserPreferenceEnabled = 1;
15		const darkmodeStylesheet = "https://a.sipoonsanomat.fi/styles/2efe7af9/styles/diks-news-darkmode.css";
16		const defaultStylesheet = "https://a.sipoonsanomat.fi/styles/2efe7af9/styles/diks-news.css";
17		const savedTheme = localStorage.getItem('theme');
18		const stylesheet = document.getElementById("diks-stylesheet");
19
20		// Check local storage for saved theme
21		if ( savedTheme == 'darkmode' ) {
22			stylesheet.href = darkmodeStylesheet;
23			document.documentElement.classList.add('diks-theme--darkmode');
24		}
25		// Check user's theme preference through an OS setting or a user agent setting
26		else if ( checkUserPreferenceEnabled && savedTheme != 'default' && ( window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ) ) {
27			stylesheet.href = darkmodeStylesheet;
28			document.documentElement.classList.add('diks-theme--darkmode');
29		}
30		else {
31			document.documentElement.classList.add('diks-theme--default');
32		}
33
34
35		// Darkmode toggle switch
36		document.addEventListener('DOMContentLoaded', function () {
37			const darkmodeButton = document.getElementById("diks-darkmode-toggler");
38
39			if (darkmodeButton) {
40				// Set darkmode button to checked if darkmode is already on
41				// Check local storage for saved theme
42				if (savedTheme == 'darkmode' ) {
43					darkmodeButton.checked = true;
44				}
45				// Check user's theme preference through an OS setting or a user agent setting
46				else if ( checkUserPreferenceEnabled && savedTheme != 'default' && ( window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ) ) {
47					darkmodeButton.checked = true;
48				}
49
50				// Change theme based on darkmode button checked/unchecked
51				darkmodeButton.addEventListener("click", function() {
52					// Swap out the URL for the different stylesheets
53					if ( stylesheet.getAttribute("href") == defaultStylesheet ) {
54						stylesheet.href = darkmodeStylesheet;
55						document.documentElement.classList.remove('diks-theme--default');
56						document.documentElement.classList.add('diks-theme--darkmode');
57						// Save theme to local storage
58						window.localStorage.setItem('theme', 'darkmode');
59					} else {
60						stylesheet.href = defaultStylesheet;
61						document.documentElement.classList.remove('diks-theme--darkmode');
62						document.documentElement.classList.add('diks-theme--default');
63						// Save theme to local storage
64						window.localStorage.setItem('theme', 'default');
65					}
66					// Dispatch event ThemeChanged when theme inside Local Storage changes
67					window.dispatchEvent(new Event("ThemeChanged"));
68				});
69			}
70		}, false);
71
72	</script>
72
73		
74		<link rel="preload" href="/gravito-cmp.js" as="script">
75			<link rel="preload" href="https://cdn.gravito.net/sdk/v6/latest/sdk.js" as="script"><link rel="preload" href="https://g335.sipoonsanomat.fi/script.js" as="script">
76			
76<script>
77		window.JankkoSSOConfig = {
78			accountOrigin: "SIPS"
79		};
80	</script>
80
81
82				
83	
83<script id="jankko-sso-script" src="https://sso.sipoonsanomat.fi/assets/jankko-sso-client.modern.min.js"></script>
83
84
85
86		
87		
88
89		
89<script>
90		// Hyphenopoly library initialization. The library will add soft-hyphen characters into the content if the
91		// browser doesn't support CSS hyphenation. For debugging on macOS Chrome: require: { 'fi': 'FORCEHYPHENOPOLY' }
92		const Hyphenopoly = {
93			require: { 'fi': 'yhdyssanahirviö' },
94			setup: {
95				defaultLanguage: "fi",
96				selectors: { '.diks-card__title': { minWordLength: 11, leftmin: 4, rightmin: 4 }, '.diks-article__headline': { minWordLength: 11, leftmin: 4, rightmin: 4 }, '.diks-parallax-content .diks-article-box .diks-sub-headline': { minWordLength: 11, leftmin: 4, rightmin: 4 } }
97			}
98		}
99		console.log('Hyphenopoly settings:', Hyphenopoly.setup)
100
101		// Helper function for hyphenating content that was added after pageload. We must query a nodelist and iterate
102		// each node because the library can't handle a nodelist.
103		// https://mnater.github.io/Hyphenopoly/Hyphenators.html
104		// https://github.com/mnater/Hyphenopoly/issues/92#issuecomment-597728300
105		const diksHyphenateContent = (containerSelector) => {
106			if (!Hyphenopoly.hyphenators) {
107				return
108			}
109			Hyphenopoly.hyphenators["HTML"].then((hyphenator) => {
110				for (const itemSelector in Hyphenopoly.setup.selectors) {
111					const containerNode = document.querySelector(containerSelector)
112					const itemNodeList = containerNode.querySelectorAll(itemSelector)
113					itemNodeList.forEach((itemNode) => { hyphenator(itemNode, itemSelector) })
114				}
115			})
116		}
117	</script>
117
118	
118<script src="https://a.sipoonsanomat.fi/styles/2efe7af9/includes/hyphenopoly/Hyphenopoly_Loader.js"></script>
118
119		
119<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
119
120		<link rel="icon" type="image/png" href="/favicon.png" sizes="96x96" /><link rel="icon" href="/favicon.ico" sizes="48x48"><link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" /><link rel="apple-touch-icon" href="/icon-180.png"/><meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" />
121		<meta name="theme-color" content="#121416" media="(prefers-color-scheme: dark)" /><link rel="alternate" type="application/rss+xml" title="Sipoon Sanomat" href="https://www.sipoonsanomat.fi/feed/rss"><meta name="robots" content="max-image-preview:large">
121<script>
122	var pageData = {};
123	
124	pageData.section = {
125			'name': 'Sovellus',
126			'uname': 'asenna',
127			'url': 'https\u003A\/\/www.sipoonsanomat.fi\/asenna\/'
128		}
129	pageData.publication = {
130		'name': 'sipoonsanomat',
131		'url': 'https\u003A\/\/www.sipoonsanomat.fi\/',
132		'engage': 'SIPS',
133		'paywallEnabled': true,
134		'registrationWallEnabled': true,
135		'env':'prod'
136	}
137	pageData.user = {}
138	pageData.companyUser = {}
139
140	function isPwa() {
141		// window.navigator.standalone = iOS
142		// window.matchMedia('(display-mode: standalone)').matches = Android/universal
143		return (window.navigator.standalone) ||
144		       (["fullscreen", "standalone", "minimal-ui"].some(
145		        function(displayMode) { return window.matchMedia('(display-mode: ' + displayMode + ')')
146		        .matches }));
147	}
148
149	pageData.general = {
150		'browseMode': (isPwa() ? 'pwa' : 'browser')
151	}
152</script>
152
153	<meta property="og:site_name" content="Sipoon Sanomat">
154	<meta property="og:locale" content="fi_FI"><meta name='description' content='Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston.'>
155<meta property='og:title' content='Sovellus | Sipoon Sanomat'>
156<meta property='og:description' content='Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston.'>
157<meta property='og:url' content='https://www.sipoonsanomat.fi/asenna/'>
158<meta property='og:type' content='webpage'><meta property='og:image' content='https://a.sipoonsanomat.fi/styles/2efe7af9/images/default/og-image-sipoonsanomat.jpg'>
159<meta property='og:image:width' content='1200'>
160<meta property='og:image:height' content='630'>
161		<link rel="manifest" href="/manifest.webmanifest">
162		<style>@media (max-width: 600px) { .gravitoCMP-footer { margin-top: 1.5em; } }</style>
163		
163<script type="text/javascript">window.cX = window.cX || {};// Async load of cx.js
164		(function(d,s,e,t){e=d.createElement(s);e.type='text/java'+s;e.async='async';
165		e.src='http'+('https:'===location.protocol?'s://s':'://')+'cdn.cxense.com/cx.js';
166		t=d.getElementsByTagName(s)[0];t.parentNode.insertBefore(e,t);})(document,'script');
167	</script>
167
168									
168<script src="https://a.sipoonsanomat.fi/styles/2efe7af9/js/blueconic/dialog.min.js"></script>
168
169		
169<script>
170			BCinst = 'blueconic';
171			BCshortcode = 'SIPS';
172			BCHighImpactAdHidingEnabled = true;
173			BCHighImpactAdSizes = [[1600,1150],[970,970],[970,540],[970,170],[320,320],[300,240],[300,220],[300,210],[1,2]];
174			BCHighImpactPrerequisiteSlots = ["gam-ad-topscroll_skin","gam-ad-topscroll_mob"];
175			BCHighImpactPrerequisiteTimeout = 5000;
176			BCGAMAdsEnabled = false;
177						initHighImpactAdHiding();
178		</script>
178<script src="https://a.sipoonsanomat.fi/styles/2efe7af9/js/blueconic/events.min.js"></script>
178
179		
179<script>
180			const BCPlatform = "web";
181			const BCChannel = 'SIPS';
182
183			const BCArticleViewProperties = {};
184			const BCSessionStartProperties = {};
185
186			BCArticleViewProperties["platform"] = BCPlatform;
187			BCArticleViewProperties["channel"] = BCChannel;
188			BCSessionStartProperties["platform"] = BCPlatform;
189			BCSessionStartProperties["channel"] = BCChannel;
190
191			const BCArticleID = pageData?.article?.id || '';
192			const BCArticleMarketingCategories = pageData?.article?.marketingCategories || [];
193			const BCArticleTopics = pageData?.article?.topics || [];
194
195			if (BCArticleID) {
196				BCArticleViewProperties["articleID"] = BCArticleID;
197			}
198
199			if (Array.isArray(BCArticleMarketingCategories) && BCArticleMarketingCategories.length > 0) {
200				BCArticleViewProperties["marketing_categories"] = BCArticleMarketingCategories.join(', ');
201			}
202
203			if (Array.isArray(BCArticleTopics) && BCArticleTopics.length > 0) {
204				BCArticleViewProperties["tags"] = BCArticleTopics.join(', ');
205			}
206
207			const BCEventParams = {
208				currentPage: '/asenna/' || null,
209				pageType: 'section' || null,
210				dependenciesTimeout: 5000,
211				inHouseAdEnabled: true,
212				articleViewEventEnabled: true,
213				articleViewProperties: BCArticleViewProperties,
214				sessionStartEventEnabled: true,
215				sessionStartProperties: BCSessionStartProperties,
216				recommendationsEnabled: false,
217				recommendationsMaxItems: 3,
218				recommendationsTitle: 'Luitko\u0020jo\u0020n\u00E4m\u00E4\u003F'
219			};
220			InitializeEventScript(BCEventParams);
221		</script>
221<script>
222			window.BCDatalayer = [];
223		</script>
223<script>
224		(function () {
225			window.BCscriptInjected = false;
226			var scriptSrc = '';
227
228							scriptSrc = 'https://g335.sipoonsanomat.fi/script.js';
229			
230			window.addEventListener(
231				"gravito:tcfv2:client",
232				function (event) {
233					let eventType = event.detail.eventType;
234					let consentUpdateEventsList = [
235						"layer1:opt-out:all",
236						"layer2:opt-out:all",
237						"layer2:opt-in:selected",
238						"layer1:opt-in:all",
239						"layer2:opt-in:all",
240						"opt-in:previously",
241					];
242					if (consentUpdateEventsList.includes(eventType) && window.BCscriptInjected === false) {
243						window.BCscriptInjected = true;
244
245						var script = document.createElement("script");
246						script.src = scriptSrc;
247						document.head.appendChild(script);
248					}
249				},
250				true
251			);
252		}());
253	</script>
253
254				
255		
255<script type='text/javascript'>
256		(function() {
257			/** CONFIGURATION START **/
258			var _sf_async_config = window._sf_async_config = (window._sf_async_config || {});
259			_sf_async_config.uid = 60754;
260			_sf_async_config.domain = location.host.replace("www.","");
261			_sf_async_config.flickerControl = false;
262			_sf_async_config.useCanonical = true;
263			_sf_async_config.useCanonicalDomain = true;
264			/** CONFIGURATION END **/
265		})();
266	</script>
266<script>
267		function configureChartbeat(userType) {
268			/** CONFIGURATION START **/
269			var _sf_async_config = window._sf_async_config = (window._sf_async_config || {});
270			_sf_async_config.sections = pageData && pageData.section ? pageData.section.name : '';
271			_sf_async_config.authors = pageData && pageData.article && Array.isArray(pageData.article.authors) ? pageData.article.authors.toString() : '';
272
273			if (userType) {
274				var _cbq = window._cbq = (window._cbq || []);
275				_cbq.push(['_acct', userType]);
276			}
277			/** CONFIGURATION END **/
278			function loadChartbeat() {
279				var e = document.createElement('script');
280				var n = document.getElementsByTagName('script')[0];
281				e.type = 'text/javascript';
282				e.async = true;
283				e.src = 'https://static.chartbeat.com/js/chartbeat.js';
284				n.parentNode.insertBefore(e, n);
285			}
286			loadChartbeat();
287		};
288
289		if (typeof JankkoSSOClient !== 'undefined') {
290			JankkoSSOClient.getSession().then(function(data) {
291				if (data && data.user && data.user.id) {
292					var userType = Array.isArray(data.permissions) && data.permissions.includes("paywall") ? 'paid' : 'lgdin';
293
294					configureChartbeat(userType);
295				} else {
296					configureChartbeat('anon');
297				}
298			}).catch(function(error) {
299				configureChartbeat('anon');
300			});
301		} else {
302			configureChartbeat('anon');
303		}
304	</script>
304
305		
305<script>
306		const gtmContainerId = 'GTM-KTJNB7R';
307		const sendDatalayerPush = Boolean(1);
308		const context = 'sec';
309
310		(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
311		new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
312		j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
313		'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
314		})(window,document,'script','dataLayer',gtmContainerId);
315
316		if (sendDatalayerPush) {
317			window.dataLayer.push({'event':'pageDataPush','pageData': window.pageData});
318		}
319
320		(async function () {
321			const paywallEnabled = window?.pageData?.publication?.paywallEnabled ?? true;
322			const registrationWallEnabled = window?.pageData?.publication?.registrationWallEnabled ?? true;
323
324			const user = {};
325			const companyUser = {};
326
327			let articleState;
328			let articlePaywall = 'free'; // free is always the safer fallback
329
330			if (context === 'art') {
331				if (window?.pageData?.article?.effectivePaywall) {
332					articlePaywall = window.pageData.article.effectivePaywall;
333				} else if (window?.pageData?.article?.paywall){
334					articlePaywall = window.pageData.article.paywall;
335				}
336
337				if ((articlePaywall === 'free' || !paywallEnabled) || (articlePaywall === "registered" && !registrationWallEnabled)) {
338					articleState = "full";
339				}
340				else {
341					articleState = 'preview';
342				}
343			}
344
345			function getCookie(name) {
346				name = name + '=';
347				const decodedCookie = decodeURIComponent(document.cookie);
348				const cookies = decodedCookie.split(';');
349				for (let i = 0; i < cookies.length; i++) {
350					const cookie = cookies[i].trim();
351					if (cookie.indexOf(name) === 0) {
352						return cookie.substring(name.length, cookie.length);
353					}
354				}
355			}
356
357			function pushDataLayerEvent() {
358				let segmentsCookie = getCookie('jankkosegments');
359
360				if (segmentsCookie) {
361					let segmentsData = JSON.parse(segmentsCookie);
362					let segments = segmentsData.segments;
363
364					if (segments && typeof segments === 'object') {
365						user.segments = segments;
366					}
367				}
368				const pageData = {
369					'user': user,
370					'companyUser': companyUser
371				};
372				if (context === 'art') {
373					pageData.article = { 'state': articleState };
374				}
375				if (sendDatalayerPush) {
376					window.dataLayer.push({'event': 'userDataPush', 'pageData': pageData });
377				}
378			}
379
380			async function modifyDatalayerData() {
381				const sessionData = await JankkoSSOClient.getSession();
382				if (!sessionData) {
383					return;
384				}
385
386				user.id = sessionData?.personal?.personal_user_id;
387				user.products = sessionData?.personal?.personal_active_products;
388				user.permissions = sessionData?.personal?.personal_permissions;
389
390				companyUser.id = sessionData?.company?.company_user_id ?? null;
391				companyUser.products = sessionData?.company?.company_active_products ?? null;
392				companyUser.permissions = sessionData?.company?.company_permissions ?? null;
393
394				const permissions = sessionData?.permissions ?? [];
395				if (context === 'art') {
396					var userIsLoggedIn = false;if ((articlePaywall != "free" && permissions.includes("paywall") && articlePaywall != "registered") || (userIsLoggedIn === true && articlePaywall === "registered")) {
397						articleState = "full";
398					}
399				}
400			}
401
402			try {
403				await modifyDatalayerData();
404			}
405			catch (error) {
406				console.warn(error);
407			}
408
409			pushDataLayerEvent();
410		}());
411
412	</script>
412
413		
414	</head>
415		<body class="diks-body diks-body--page-type-apps">
416		<!-- Google Tag Manager (noscript) -->
vendor: 72 bytes, lines 416-417
416
417    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
417GTM-KTJNB7R
vendor: 95 bytes, lines 417-419
417"
418        height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
419    
419<!-- End Google Tag Manager (noscript) -->
420		
420<script src='/gravito-cmp.js'></script>
420
421
422					
423		
424		
425										<header id="main-header" class="diks-header diks-header diks-header--is-fixed">
426	<div class="diks-skip-link-navigation diks-skip-link-navigation--top">
427		<ul class="diks-navigation diks-navigation--skip-links">
428							<li class="diks-navigation__item">
429					<a class="diks-button diks-button--primary diks-a11y__screen-reader diks-a11y__screen-reader--focusable" href="#sisalto" >Siirry suoraan sisältöön</a>
430				</li>
431					</ul>
432	</div>
433
434	<div class="diks-header-wrapper">
435		<div class="diks-container diks-container--header">
436			<div class="diks-header-container"><div class="diks-header__navigation-container diks-header__navigation-container--left">
437						<button class="diks-button diks-button--icon-only diks-button--ghost diks-navigation__link js-diks-toggler diks-dropdown-toggler diks-dropdown-toggler--main" id="diks-dropdown-toggle" data-toggle="diks-dropdown-navigation" aria-expanded="false" aria-controls="diks-dropdown-navigation" aria-label="Valikko"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
438  <path fill-rule="evenodd" d="M22 6H2V4H22V6ZM22 13H2V11H22V13ZM22 20H2V18H22V20Z" clip-rule="evenodd"/>
439</svg>
440</span><span class="diks-icon diks-icon--size-m diks-icon--hidden" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
441  <path fill-rule="evenodd" d="M10.5858 12L4.2218 5.63603L5.63602 4.22182L12 10.5858L18.3639 4.22183L19.7782 5.63605L13.4142 12L19.7782 18.364L18.3639 19.7782L12 13.4142L5.63602 19.7782L4.2218 18.364L10.5858 12Z" clip-rule="evenodd"/>
442</svg>
443</span></button>
444
445		<div class="diks-dropdown-navigation" id="diks-dropdown-navigation">
446		<button id="diks-close-dropdown-main-nav" class="diks-button diks-button--outline diks-dropdown-navigation__close-button diks-a11y__screen-reader diks-a11y__screen-reader--focusable">Sulje valikko</button><div class="diks-dropdown-navigation__sign-container">
447				<img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/keskisuomalainen-sign.svg" class="diks-logo diks-dropdown-navigation__sign" alt="Keskisuomalainen Oyj">
448			</div><form id="dropdown-navigation-search" name="dropdownnavigationsearch" class="diks-form diks-form--fluid" action="/haku/" method="get">
449					<div class="diks-form__field-wrapper diks-form__field-wrapper--padding-right diks-form__field-wrapper--required"><input class="diks-form__field" type="search" name="q" id="dropdown-navigation-searchSearch1"   aria-label="Haku" placeholder="Hae sivustolta" required  value=""></div>
450
451						<div class="diks-form__field-wrapper diks-form__field-wrapper--submit-button-icon-only">
452		<button class="diks-form__submit" type="submit" id="dropdown-navigation-searchSubmitbutton2"><span class="diks-icon diks-icon--color-primary" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
453  <path fill-rule="evenodd" d="M9.5 4C6.46243 4 4 6.46243 4 9.5C4 12.5376 6.46243 15 9.5 15C12.5376 15 15 12.5376 15 9.5C15 6.46243 12.5376 4 9.5 4ZM2 9.5C2 5.35786 5.35786 2 9.5 2C13.6421 2 17 5.35786 17 9.5C17 11.2106 16.4273 12.7874 15.4632 14.0493L19.7782 18.3642L18.3639 19.7784L14.049 15.4634C12.7872 16.4274 11.2105 17 9.5 17C5.35786 17 2 13.6421 2 9.5Z" clip-rule="evenodd"/>
454</svg>
455</span>Hae
456		</button>
457	</div>
458			</form>	<nav class="diks-navigation-wrapper diks-navigation-wrapper--border-bottom diks-navigation-wrapper--border-top" ><ul class="diks-navigation diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-navigation--size-s"  id="dropdown-highlights-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/asenna/">Sovellus</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/">Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul>
459		</nav>	<nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-bottom" ><ul class="diks-navigation diks-navigation--no-active-links diks-navigation--size-s"  id="dropdown-customer-upper-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/sipoon-sanomat/"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
460  <path d="M17 8H22V17H19.1875V20.8125L14.1045 17H9V13.4307L4.4375 17.0811V13H2V3H17V8ZM17 13H11V15H14.7705L17.1875 16.8125V15H20V10H17V13ZM4 11H6.4375V12.918L8.5625 11.2188L8.83691 11H15V5H4V11Z"/>
461</svg>
462</span>Asiakaspalvelu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/sipoon-sanomat/yhteystiedot/juttuvinkki/"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
463  <path fill-rule="evenodd" d="M7.38197 4H16.618L17.618 6H22V20H2V6H6.38197L7.38197 4ZM8.61803 6L7.61803 8H4V18H20V8H16.382L15.382 6H8.61803ZM12 11C10.8954 11 10 11.8954 10 13C10 14.1046 10.8954 15 12 15C13.1046 15 14 14.1046 14 13C14 11.8954 13.1046 11 12 11ZM8 13C8 10.7909 9.79086 9 12 9C14.2091 9 16 10.7909 16 13C16 15.2091 14.2091 17 12 17C9.79086 17 8 15.2091 8 13Z" clip-rule="evenodd"/>
464</svg>
465</span>Lähetä juttuvinkki</a></li></ul>
466		</nav>	<nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--light"  id="dropdown-section-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/">Etusivu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/">Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/">Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mina-sipoolainen">Minä sipoolainen</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat">Paikalliset yrittäjät</a></li><li class="diks-navigation__item " >
466<a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Liikunta_ja_urheilu">Liikunta ja urheilu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa">Uusimaa 360</a></li></ul>
467		</nav><!-- ESI start element "recommendedTopics" generated at 02-10-2026 15:12:47.915220 -->	<nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-top" ><ul class="diks-navigation diks-navigation--light diks-navigation--size-s" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/miten-on">Miten on?</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/vuoden-sipoolainen">Vuoden sipoolainen</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset">Hyvät uutiset</a></li></ul>
468		</nav><!-- ESI end element "recommendedTopics" --><!-- ESI start element "promotedAdvertisers" generated at 02-10-2026 15:13:00.474942 --><!-- ESI end element "promotedAdvertisers" -->	<nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-top" ><h2 class="diks-navigation__title">Yhteystiedot</h2><ul class="diks-navigation diks-navigation--light diks-navigation--size-s"  id="dropdown-customer-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://meks.fi/mainonta/alueet/etela-suomen-media/">Mediamyynti</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/sipoon-sanomat/yhteystiedot/">Kaikki yhteystiedot</a></li></ul>
469		</nav><div class="diks-navigation-wrapper diks-navigation-wrapper--divider-top"><h2 class="diks-navigation__title">Ulkoasu</h2><label for="diks-darkmode-toggler" class="diks-form__switch">
470					<span class="diks-form__switch-label"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
471  <path fill-rule="evenodd" d="M13.7547 1.76065L11.7581 3.75666C10.6708 4.8436 10 6.34252 10 8C10 11.3137 12.6863 14 16 14C17.6575 14 19.1564 13.3292 20.2433 12.2419L22.2394 10.2453L21.9451 13.0531C21.4182 18.0815 17.1674 22 12 22C6.47715 22 2 17.5229 2 12C2 6.83263 5.91855 2.58178 10.9469 2.05488L13.7547 1.76065ZM8.70749 4.70657C5.93176 5.9617 4 8.75566 4 12C4 16.4183 7.58172 20 12 20C15.2443 20 18.0383 18.0682 19.2934 15.2925C18.289 15.7468 17.1738 16 16 16C11.5817 16 8 12.4183 8 8C8 6.82623 8.25316 5.71105 8.70749 4.70657Z" clip-rule="evenodd"/>
472</svg>
473</span>Käytä tummaa tilaa</span>
474					<div class="diks-form__switch-wrapper">
475						<input id="diks-darkmode-toggler" class="diks-form__switch-input" type="checkbox">
476						<span class="diks-form__switch-slider"></span>
477					</div>
478				</label>
479			</div></div>	<nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--main diks-navigation--size-s diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-hide-below-large" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
480  <path fill-rule="evenodd" d="M12 4a8 8 0 100 16 8 8 0 000-16zM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12zm9-6h2v5.586l2.707 2.707-1.414 1.414L11 12.414V6z" clip-rule="evenodd"/>
481</svg>
482</span>Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
483  <path fill-rule="evenodd" d="M11.03 3.455c1.168-1.438 3.495-.652 3.55 1.2l.117 3.845h6a1.25 1.25 0 0 1 1.229 1.484l-1.905 10A1.25 1.25 0 0 1 18.793 21H9.06a1.25 1.25 0 0 1-.559-.132L6.764 20H3.25C2.56 20 2 19.44 2 18.75v-8.5C2 9.56 2.56 9 3.25 9h3.274l4.506-5.545ZM8 10.355v8.027L9.236 19h8.936l1.62-8.5h-5.58a1.5 1.5 0 0 1-1.499-1.455l-.131-4.33L8 10.356Zm10.056 9.255ZM4 11v7h2v-7H4Zm14.793 8.75.145.027Z" clip-rule="evenodd"/>
484</svg>
485</span>Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
486  <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/>
487</svg>
488</span>Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-above-medium diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul>
489		</nav></div><div class="diks-header__logo-container"><a class="diks-logo__link diks-header__logo-link diks-header__main-logo-link" href="/"><img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/sipoonsanomat.svg" class="diks-logo diks-logo--default diks-header__logo diks-header__main-logo" alt="Sipoon Sanomat"><img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/sipoonsanomat-white.svg" class="diks-logo diks-logo--darkmode diks-header__logo diks-header__main-logo" alt="Sipoon Sanomat"></a>
490					</div><div class="diks-header__navigation-container diks-header__navigation-container--right"><a class="diks-bc-order-button diks-button diks-button--primary diks-button--size-m diks-hide-from-subscribers diks-hide-below-medium " href="/jatka/">Tilaa</a><div class="diks-user-navigation-wrapper">
491	<button class="diks-button diks-button--icon-only diks-button--ghost diks-navigation__link diks-dropdown-toggler diks-dropdown-toggler--user" aria-expanded="false" id="diks-sso-user" data-diks-toggle="diks-user-navigation" data-diks-toggle-class="diks-user-navigation" aria-controls="diks-user-navigation"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
492  <path fill-rule="evenodd" d="M4 12a8 8 0 1 1 13.496 5.814c-1.216-1.593-3.262-2.602-5.491-2.602-2.231 0-4.28 1.011-5.495 2.607A7.978 7.978 0 0 1 4 12Zm4.04 6.953A7.963 7.963 0 0 0 12 20a7.964 7.964 0 0 0 3.966-1.05c-.83-1.087-2.254-1.84-3.961-1.84-1.71 0-3.135.754-3.965 1.843ZM12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2Zm.005 5.898c-1.247 0-2.305 1.049-2.305 2.4 0 1.353 1.058 2.402 2.305 2.402s2.305-1.05 2.305-2.401c0-1.352-1.058-2.4-2.305-2.4Zm-4.203 2.4C7.802 7.952 9.658 6 12.005 6c2.347 0 4.203 1.95 4.203 4.299 0 2.348-1.856 4.299-4.203 4.299-2.347 0-4.203-1.951-4.203-4.3Z" clip-rule="evenodd"/>
493</svg>
494</span><span class="diks-icon diks-icon--size-m diks-icon--hidden" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
495  <path fill-rule="evenodd" d="M10.5858 12L4.2218 5.63603L5.63602 4.22182L12 10.5858L18.3639 4.22183L19.7782 5.63605L13.4142 12L19.7782 18.364L18.3639 19.7782L12 13.4142L5.63602 19.7782L4.2218 
49518.364L10.5858 12Z" clip-rule="evenodd"/>
496</svg>
497</span></button>
498
499	<div class="diks-navigation diks-sub-navigation diks-user-navigation" id="diks-user-navigation">
500		<button id="diks-close-dropdown-user-nav" class="diks-button diks-button--outline diks-dropdown-navigation__close-button diks-a11y__screen-reader diks-a11y__screen-reader--focusable">Sulje valikko</button>
501	<p id="diks-sso-username" class="diks-user-navigation__username diks-hide-from-company-subscribers"></p><p class="diks-user-navigation__username diks-show-for-company-subscribers">Yritystilaus tunnistettu</p><div class="diks-show-for-company-subscribers"><p>Voit käyttää palvelun kaikkia sisältöjä vapaasti. Jos haluat kommentoida, kirjaudu sisään henkilökohtaisella Mediatunnuksella.</p></div>	<ul class="diks-navigation diks-navigation--size-m"  id="diks-sso-links"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="javascript:window.gravito.cmp.openPreferences();">Evästevalinnat</a></li></ul>
502	</div>
503</div>
504				</div>
505			</div>
506		</div>
507	</div><div class="diks-section-navigation-wrapper">
508			<div class="diks-container diks-container--narrow-mobile diks-container--full-width-before-l">
509					<nav class="diks-navigation-wrapper diks-navigation-wrapper--border-bottom"  aria-label="Osastovalikko"><ul class="diks-navigation diks-navigation--row diks-navigation--light diks-navigation--centered diks-navigation--mobile-row diks-navigation--draggable diks-navigation--size-xs diks-navigation--active-subtle"  id="osastovalikko"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mina-sipoolainen"draggable="false">Minä sipoolainen</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja"draggable="false">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat"draggable="false">Paikalliset yrittäjät</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset"draggable="false">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Liikunta_ja_urheilu"draggable="false">Liikunta ja urheilu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa"draggable="false">Uusimaa 360</a></li></ul>
510		</nav>
511			</div>
512		</div><div class="diks-quicklinks-wrapper">
513			<div class="diks-container diks-container--narrow-mobile">
514					<nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--main diks-navigation--size-s diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-navigation--centered diks-hide-above-large" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
515  <path fill-rule="evenodd" d="M12 4a8 8 0 100 16 8 8 0 000-16zM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12zm9-6h2v5.586l2.707 2.707-1.414 1.414L11 12.414V6z" clip-rule="evenodd"/>
516</svg>
517</span>Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
518  <path fill-rule="evenodd" d="M11.03 3.455c1.168-1.438 3.495-.652 3.55 1.2l.117 3.845h6a1.25 1.25 0 0 1 1.229 1.484l-1.905 10A1.25 1.25 0 0 1 18.793 21H9.06a1.25 1.25 0 0 1-.559-.132L6.764 20H3.25C2.56 20 2 19.44 2 18.75v-8.5C2 9.56 2.56 9 3.25 9h3.274l4.506-5.545ZM8 10.355v8.027L9.236 19h8.936l1.62-8.5h-5.58a1.5 1.5 0 0 1-1.499-1.455l-.131-4.33L8 10.356Zm10.056 9.255ZM4 11v7h2v-7H4Zm14.793 8.75.145.027Z" clip-rule="evenodd"/>
519</svg>
520</span>Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
521  <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/>
522</svg>
523</span>Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-above-medium diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul>
524		</nav>
525			</div>
526		</div><div id="diks-dropdown-navigation-shade" class="diks-dropdown-navigation-shade"></div></header>
526<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
526
527	
527<script>
528	// Fix forEach for IE
529	if (window.NodeList && !NodeList.prototype.forEach) {
530		NodeList.prototype.forEach = Array.prototype.forEach;
531	}
532
533	// Element.closest() needs a polyfill for older browsers.
534	// While we only need the closest() functionality for mobile browsers,
535	// we don't want the code to fail even on old desktop browsers.
536	// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
537	// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility
538	if (!Element.prototype.matches) {
539		Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
540	}
541
542	if (!Element.prototype.closest) {
543		Element.prototype.closest = function(s) {
544			var el = this;
545
546			do {
547				if (el.matches(s)) return el;
548				el = el.parentElement || el.parentNode;
549			} while (el !== null && el.nodeType === 1);
550			return null;
551		};
552	}
553
554		(function () {
555		if (typeof JankkoSSOClient !== 'undefined') {
556			var stringToHTML = function (htmlString) {
557				var div = document.createElement('div');
558				div.innerHTML = htmlString.trim();
559				return div.firstChild;
560			};
561
562			var showUserRelatedItems = function(personalData) {
563				var usernameElement = document.querySelector('#diks-sso-username');
564				if (usernameElement) {
565					usernameElement.innerHTML = personalData.full_name;
566				}
567
568				var linksElement = document.querySelector('#diks-sso-links');
569				if (linksElement) {
570					var myAccountLink = stringToHTML('<li class="diks-navigation__item"><a class="diks-navigation__link" href="'+JankkoSSOClient.serviceUrls.myAccount+'">Omat tiedot</a></li>');
571					var logoutForm = stringToHTML('<li class="diks-navigation__item diks-navigation__item--logout"><form id="logout-form" action="'+JankkoSSOClient.serviceUrls.logout+'" method="post"><input class="diks-navigation__link" type="submit" value="Kirjaudu ulos"></form></li>');
572					linksElement.insertBefore(myAccountLink, linksElement.childNodes[0]);
573					linksElement.appendChild(logoutForm);
574				}
575
576				var htmlElement = document.querySelector('.diks-user--is-not-logged-in'); // Class is set to main html element
577				if (htmlElement) {
578					htmlElement.classList.replace('diks-user--is-not-logged-in', 'diks-user--is-logged-in');
579				}
580			}
581
582			var showMenuLinksForLoggedOutUser = function() {
583				const linksElement = document.querySelector('#diks-sso-links');
584				if (!linksElement) {
585					return;
586				}
587
588				// Pidetään vain tietyt query-parametrit. Alunperin tässä poistettiin kaikki query-parametrit.
589				// @todo Selvitetään voisiko tässä sallia kaikki query-parametrit.
590				const currentUrlObject = new URL(window.location.href);
591				const returnUrlObject = new URL(`${currentUrlObject.origin}${currentUrlObject.pathname}`);
592				const allowedParams = ['limit-active-products'];
593				allowedParams.forEach(function(name) {
594					if (currentUrlObject.searchParams.get(name)) {
595						returnUrlObject.searchParams.set(name, currentUrlObject.searchParams.get(name));
596					}
597				});
598
599				const loginPageUrlObject = new URL(`${window.location.origin}/kirjaudu/`);
600				loginPageUrlObject.searchParams.set('returnUrl', returnUrlObject.toString());
601				const loginLinkString = `<li class="diks-navigation__item"><a class="diks-navigation__link" href="${loginPageUrlObject.toString()}">Kirjaudu</a></li>`;
602
603				linksElement.insertBefore(stringToHTML(loginLinkString), linksElement.childNodes[0]);
604			}
605
606			var showCompanyUserRelatedItems = function(companyData) {
607				var htmlElement = document.querySelector('.diks-user--is-not-company-subscriber'); // Class is set to main html element
608				var permissions = companyData?.company_permissions || [];
609				if (htmlElement && permissions.length) {
610					htmlElement.classList.replace('diks-user--is-not-company-subscriber', 'diks-user--is-company-subscriber');
611				}
612			}
613
614			document.addEventListener("DOMContentLoaded", async function() {
615				try {
616					const data = await JankkoSSOClient.getSession();
617					if (data.company?.company_user_id) {
618						showCompanyUserRelatedItems(data.company);
619					}
620					if (data.personal?.personal_user_id) {
621						showUserRelatedItems(data.personal);
622					} else {
623						showMenuLinksForLoggedOutUser();
624					}
625				} catch (error) {
626					showMenuLinksForLoggedOutUser();
627				}
628			});
629		}
630	}());
631
632
633	//////////////////////////////////////////////////////////////////////////////////////////
634	// NAVIGATIONS
635	//////////////////////////////////////////////////////////////////////////////////////////
636
637	// Toggle icon inside a toggler
638	function toggleTogglerIcon(toggler) {
639		togglerIcons = toggler.querySelectorAll('.diks-icon');
640		if ( togglerIcons.length > 1 ) {
641			for (var j= 0; j < togglerIcons.length; j++) {
642				togglerIcons[j].classList.toggle('diks-icon--hidden');
643			}
644		}
645	}
646
647	// Function for closing all dropdown navigations
648	function closeAllDropdownNavigations() {
649		closeMainDropdownNavigation();
650		closeUserDropdownNavigation();
651	}
652
653	// Close main nav or user nav if hidden screen reader only close navigation button is clicked
654	let closeDropdownMainNav = document.getElementById('diks-close-dropdown-main-nav');
655	let closeDropdownUserNav = document.getElementById('diks-close-dropdown-user-nav');
656	if ( closeDropdownMainNav ) {
657		closeDropdownMainNav.addEventListener('click', function() {
658			closeMainDropdownNavigation();
659		});
660	}
661	if ( closeDropdownUserNav ) {
662		closeDropdownUserNav.addEventListener('click', function(e) {
663			e.stopPropagation();
664			closeUserDropdownNavigation();
665		});
666	}
667
668	// Trap focus inside opened dropdown navigation
669	document.addEventListener('keydown', function(event) {
670		// Initialize variables
671		var ssoLinks = document.getElementById('diks-sso-links');
672		var linksUserNav = "";
673		var firstElUserNav = "";
674		var lastElUserNav = "";
675		var mainDropdownLastNavLinks = document.getElementById('dropdown-customer-nav'); // Last navigation element inside of main dropdown navigation
676		var linksMainDropdownNav = "";
677		var firstElMainDropdownNav = ""
678		var lastElMainDropdownNav = "";
679
680		// Set user nav variable values if SSO links exist
681		if (ssoLinks) {
682			linksUserNav = ssoLinks.querySelectorAll('.diks-navigation__link');
683			firstElUserNav = document.getElementById('diks-close-dropdown-user-nav');
684			lastElUserNav = linksUserNav[linksUserNav.length - 1];
685		}
686
687		// Set main dropdown nav variable values if main dropdown last nav links exist
688		if (mainDropdownLastNavLinks) {
689			linksMainDropdownNav = mainDropdownLastNavLinks.querySelectorAll('.diks-navigation__link');
690			firstElMainDropdownNav = document.getElementById('diks-close-dropdown-main-nav');
691			lastElMainDropdownNav = linksMainDropdownNav[linksMainDropdownNav.length - 1];
692		}
693
694		// If darkmode-toggler is found set it as the last element of main dropdown nav
695		if ( document.getElementById('diks-darkmode-toggler') ) {
696			lastElMainDropdownNav = document.getElementById('diks-darkmode-toggler');
697		}
698
699		// Close all dropdown navigations & reposition fixed header when ESC key is pressed
700		if (event.key === "Escape" || event.key === "Esc") {
701			closeAllDropdownNavigations();
702		}
703		// Trap focus inside user navigation and/or main dropdown navigation when they are open
704		if (event.keyCode === 9) {
705			if (event.shiftKey && (document.activeElement === firstElUserNav || document.activeElement === firstElMainDropdownNav)) {
706				event.preventDefault();
707				if (document.activeElement === firstElUserNav) {
708					lastElUserNav.focus();
709				}
710				else if ( document.activeElement === firstElMainDropdownNav ) {
711					lastElMainDropdownNav.focus();
712				}
713			}
714			else if (!event.shiftKey && (document.activeElement === lastElUserNav || document.activeElement === lastElMainDropdownNav)) {
715				event.preventDefault();
716				if (document.activeElement === lastElUserNav) {
717					firstElUserNav.focus();
718				}
719				else if ( document.activeElement === lastElMainDropdownNav ) {
720					firstElMainDropdownNav.focus();
721				}
722			}
723		}
724	});
725
726
727	//////////////////////////////////////////////////////////////////////////////////////////
728	// User navigation
729	//////////////////////////////////////////////////////////////////////////////////////////
730
731	let userDropdownNavigation = document.getElementById('diks-user-navigation'); // user dropdown navigation
732	let userDropdownNavigationToggler = document.getElementById('diks-sso-user'); // user dropdown navigation toggler button (opens and closes user dropdown navigation)
733	let userDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside user dropdown navigation
734
735	// Close user dropdown navigation if hidden screen-reader-only close button is clicked
736	if ( userDropdownNavigationCloseButton ) {
737		userDropdownNavigationCloseButton.addEventListener('click', function() {
738			closeUserDropdownNavigation();
739		});
740	}
741
742	function closeUserDropdownNavigation() {
743		if (userDropdownNavigation) {
744			if (userDropdownNavigation.classList.contains('diks-user-navigation--is-open')) {
745				// Close user dropdown nav by removing --is-open class
746				userDropdownNavigation.classList.remove('diks-user-navigation--is-open');
747				// Remove --is-open class from user dropdown navigation toggler
748				userDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open');
749				// Toggle icon
750				toggleTogglerIcon(userDropdownNavigationToggler);
751
752				// Set aria-expanded to false for user dropdown toggler
753				userDropdownNavigationToggler.setAttribute('aria-expanded', 'false');
754			}
755		}
756	}
757
758	// User Navigation Dropdown
759	if (userDropdownNavigation) {
760		let userDropdownNavigationAriaControls = userDropdownNavigationToggler.getAttribute('data-diks-toggle'); // aria-controls value for user dropown navigation toggler
761		userDropdownNavigationToggler.setAttribute('aria-controls', userDropdownNavigationAriaControls);
762		userDropdownNavigationToggler.addEventListener('click', function(e) {
763			e.preventDefault();
764			// If the main dropdown navigation is already open (contains --is-open class) close it
765			if ( (userDropdownNavigation).classList.contains('diks-user-navigation--is-open') ) {
766				closeUserDropdownNavigation();
767			}
768			// If the main dropdown navigation isn't open (doesn't contain --is-open class) open it
769			else {
770				// If other toggles are open, close them
771				document.querySelectorAll('.diks-user-navigation--is-open').forEach(function(item) {
772					item.classList.remove('diks-user-navigation--is-open');
773					userDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open');
774				});
775
776				// Toggle icon
777				toggleTogglerIcon(userDropdownNavigationToggler);
778
779				// Set aria-expanded
780				userDropdownNavigationToggler.setAttribute('aria-expanded', 'true');
781
782				// Open this toggle
783				userDropdownNavigation.classList.add('diks-user-navigation--is-open');
784
785				// Close main dropdown navigation if it's open
786				closeMainDropdownNavigation();
787
788				// Add event listener to window when user nav toggler is clicked and user nav is open
789				window.addEventListener('click', function(e){
790					if (document.querySelector('.diks-user-navigation-wrapper').contains(e.target)){
791						// Clicked inside user nav, do nothing
792					}
793					else {
794						// Clicked outside user nav, close user nav
795						closeUserDropdownNavigation();
796					}
797				});
798
799			}
800		});
801	}
802
803	//////////////////////////////////////////////////////////////////////////////////////////
804	// Main navigation
805	//////////////////////////////////////////////////////////////////////////////////////////
806
807	let mainDropdownNavigation = document.getElementById('diks-dropdown-navigation'); // main dropdown navigation
808	let mainDropdownNavigationToggler = document.getElementById('diks-dropdown-toggle'); // main dropdown navigation toggler button (opens and closes main dropdown navigation)
809	let mainDropdownNavigationShade = document.querySelector('.diks-dropdown-navigation-shade'); // shade effect that is visible when main dropdown navigation is open
810	let mainDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside main dropdown navigation
811
812	// Close main dropdown navigation if hidden screen-reader-only close button is clicked
813	if ( mainDropdownNavigationCloseButton ) {
814		mainDropdownNavigationCloseButton.addEventListener('click', function() {
815			closeMainDropdownNavigation();
816		});
817	}
818
819	// Function for closing main dropdown navigation
820	function closeMainDropdownNavigation() {
821		// Main dropdown navigation
822		if (mainDropdownNavigation) {
823			if (mainDropdownNavigation.classList.contains('diks-dropdown-navigation--is-open')) {
824				// Close main dropdown nav by removing --is-open class
825				mainDropdownNavigation.classList.remove('diks-dropdown-navigation--is-open');
826				// Remove --is-open class from main dropdown navigation toggler
827				mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open');
828				// Toggle icon
829				toggleTogglerIcon(mainDropdownNavigationToggler);
830
831				// Set aria-expanded to false for main dropdown toggler
832				mainDropdownNavigationToggler.setAttribute('aria-expanded', 'false');
833
834				// Remove --is-open class from body
835				document.body.classList.remove('diks-body--dropdown-navigation-is-open');
836
837				// Turn off shade effect
838				mainDropdownNavigationShade.classList.remove('diks-dropdown-navigation-shade--is-visible');
839			}
840		}
841	}
842
843
844	// Main Navigation Dropdown
845	if (mainDropdownNavigation) {
846		let mainDropdownNavigationAriaControls = mainDropdownNavigationToggler.getAttribute('data-toggle'); // aria-controls value for main dropown navigation toggler
847		mainDropdownNavigationToggler.setAttribute('aria-controls', mainDropdownNavigationAriaControls);
848		mainDropdownNavigationToggler.addEventListener('click', function(e) {
849			e.preventDefault();
850			// If the main dropdown navigation is already open (contains --is-open class) close it
851			if ( (mainDropdownNavigation).classList.contains('diks-dropdown-navigation--is-open') ) {
852				closeMainDropdownNavigation();
853			}
854			// If the main dropdown navigation isn't open (doesn't contain --is-open class) open it
855			else {
856				// If other toggles are open, close them
857				document.querySelectorAll('.diks-dropdown-navigation--is-open').forEach(function(item) {
858					item.classList.remove('diks-dropdown-navigation--is-open');
859					mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open');
860				});
861
862				// Toggle icon
863				toggleTogglerIcon(mainDropdownNavigationToggler);
864
865				// Set aria-expanded
866				mainDropdownNavigationToggler.setAttribute('aria-expanded', 'true');
867
868				// Open this toggle
869				mainDropdownNavigation.classList.add('diks-dropdown-navigation--is-open');
870				// Add is-open class to body
871				document.body.classList.add('diks-body--dropdown-navigation-is-open');
872				// Turn on shade effect
873				mainDropdownNavigationShade.classList.add('diks-dropdown-navigation-shade--is-visible');
874
875				// Close main Dropdown Navigation when visible shade area is clicked
876				document.querySelector('.diks-dropdown-navigation-shade--is-visible').addEventListener('click', function() {
877					closeMainDropdownNavigation();
878				});
879
880				// Close user dropdown navigation if it's open
881				closeUserDropdownNavigation();
882
883			}
884		});
885	}
886
887
888</script>
888
889
890				
891																				
892																							
893																								
894																								
895																								
896							<div class="diks-note-wrapper "><div class="diks-container diks-container--narrower-mobile">
897			<div id="diks-segment-notes"></div><div id="diks-bc-notes"></div></div></div>
897<script>
898	let segmentTeasersContainer = document.getElementById("diks-segment-notes");
899
900	(function() {
901		function getCookie(name) {
902			name = name + '=';
903			const decodedCookie = decodeURIComponent(document.cookie);
904			const cookies = decodedCookie.split(';');
905
906			for (let i = 0; i < cookies.length; i++) {
907				const cookie = cookies[i].trim();
908				if (cookie.indexOf(name) == 0) {
909					return cookie.substring(name.length, cookie.length);
910				}
911			}
912		}
913
914		function injectSegmentTeasers(segmentsQueryString) {
915			var xhttp = new XMLHttpRequest();
916
917			xhttp.onreadystatechange = function() {
918				if (this.readyState == 4 && this.status == 200) {
919					var segmentTeasers = this.responseText.trim();
920
921					if (segmentTeasers) {
922						if (segmentTeasersContainer) {
923							segmentTeasersContainer.innerHTML = segmentTeasers;
924						}
925					}
926					else {
927						// Remove segment teaser container if there are no segment teasers
928						if (segmentTeasersContainer) {
929							segmentTeasersContainer.remove();
930						}
931					}
932				}
933			};
934
935			xhttp.open("GET", "/.ajax/segmentTeaser?" + segmentsQueryString, true);
936			xhttp.send();
937		}
938
939		var segmentsCookie = getCookie('jankkosegments');
940
941		if (segmentsCookie) {
942			var segmentsData = JSON.parse(segmentsCookie);
943			var segments = segmentsData.segments;
944
945			if (segments && typeof segments === 'object') {
946				var segmentsQueryString = "";
947
948				Object.keys(segments).forEach(function(key, index) {
949					segmentsQueryString = index === 0 ? "" : segmentsQueryString + "&";
950					var value = segments[key];
951
952					if (Array.isArray(value)) {
953						value = value.join(',');
954					}
955
956					segmentsQueryString = segmentsQueryString + key + "=" + value;
957				});
958
959				injectSegmentTeasers(segmentsQueryString);
960			}
961		}
962		else {
963			// Remove segment teaser container if there are no segment teasers
964			if (segmentTeasersContainer) {
965				segmentTeasersContainer.remove();
966			}
967		}
968	})();
969</script>
969
970
971	<div class="diks-custom-page diks-apps">
972		<div class="diks-container">
973			<div class="diks-grid">
974				<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-16"><nav aria-label="Murupolku">
975		<ul class="diks-breadcrumb"><li class="diks-breadcrumb__item"><a class="diks-breadcrumb__link" href="/">Etusivu</a></li><li class="diks-breadcrumb__item"><span class="diks-breadcrumb__sub-item">Sovellus</span></li></ul>
976	</nav></div>
977			</div>
978			<main id="sisalto">
979				<div class="diks-apps__content-wrapper">
980					<div class="diks-grid">
981						<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div>
982		<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-12">
983				<h1 class="diks-title diks-title--size-3xl" >Sovellus</h1>
984		</div>
985		<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div>
986						<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div><div class="diks-apps-installation-wrapper diks-column diks-column--span-4 diks-column--m-span-4 diks-column--l-span-6 diks-column--xl-span-6">
987				<div class="diks-apps__icon-wrapper">
988					<span class="diks-icon diks-icon--size-l diks-icon--color-primary" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
989  <path fill-rule="evenodd" d="M5 2H19V22H5V2ZM7 4V20H17V4H7ZM15 19H9V17H15V19Z" clip-rule="evenodd"/>
990</svg>
991</span>
992				</div>	<h2 class="diks-title diks-title--size-xl" >Sovellus</h2><p>Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston. Asenna sovellus laitteesi sovelluskaupasta.</p><div class="diks-apps-image-wrapper">
993						<a class="diks-apps__app-link diks-hide-on-android" href="https://apps.apple.com/fi/app/sipoon-sanomat/id6740268452"><img class="diks-apps__app-image" src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/default/appstore-badge.svg" alt="Lataa sovellus App Storesta"></a>
994						<a class="diks-apps__app-link diks-hide-on-ios" href="https://play.google.com/store/apps/details?id=fi.media.sipoonsanomat"><img class="diks-apps__app-image" src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/default/google-play-badge.svg" alt="Lataa sovellus Google Play -kaupasta"></a>
995					</div></div>
996								<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div>
997					</div>
998				</div>
999			</main>
1000		</div>
1001	</div>
1002					
1003								<footer class="diks-footer"><div class="diks-container diks-container--narrow-mobile diks-container--full-width-before-l">
1004			<div class="diks-footer__top">	<nav class="diks-navigation-wrapper "  aria-label="Osastovalikko"><ul class="diks-navigation diks-navigation--row diks-navigation--light diks-navigation--centered diks-navigation--mobile-row diks-navigation--draggable diks-navigation--size-xs diks-navigation--active-subtle" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mina-sipoolainen"draggable="false">Minä sipoolainen</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja"draggable="false">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat"draggable="false">Paikalliset yrittäjät</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset"draggable="false">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Liikunta_ja_urheilu"draggable="false">Liikunta ja urheilu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa"draggable="false">Uusimaa 360</a></li></ul>
1005		</nav></div>
1006		</div><div class="diks-container"><div class="diks-footer__main">
1007				<div class="diks-grid">
1008					<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-4">
1009						<p><img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/sipoonsanomat.svg" class="diks-logo diks-logo--default diks-footer__main-logo--narrow" alt="Sipoon Sanomat"><img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/sipoonsanomat-white.svg" class="diks-logo diks-logo--darkmode diks-footer__main-logo--narrow" alt="Sipoon Sanomat"></p>
1010						<p><strong>Postiosoite:</strong> Lundinkatu 8, 06100 Porvoo<br><strong>Käyntiosoite:</strong> Lundinkatu 8, 06100 Porvoo (käynti Runeberginkatu 31)<br><strong>Vastaava päätoimittaja:</strong> Ulla Yliherne</p><div class="diks-footer__main-secondary-logos-container"><div class="diks-footer__main-secondary-logo"><a href="https://vastuullistajournalismia.fi/"><img src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/vastuullista-journalismia.png" loading="lazy" alt="Vastuullisen journalismin merkki kertoo, että sitä käyttävä media on sitoutunut noudattamaan Julkisen sanan neuvoston laatimia Journalistin ohjeita."></a></div></div><div class="diks-footer__main-links-wrapper">
1011		<div class="diks-column diks-column--span-2"><a class="diks-footer__main-link" href="https://www.keskisuomalainen.com/tietosuojalauseke/">Tietosuojalauseke</a><a class="diks-footer__main-link" href="javascript:window.gravito.cmp.openPreferences();">Evästevalinnat</a><a class="diks-footer__main-link" href="https://www.keskisuomalainen.com/kayttoehdot/">Käyttöehdot</a><a class="diks-footer__main-link" href="https://keskisuomalainen.com/medianvapausasetus/">Medianvapausasetus</a><a class="diks-footer__main-link" href="https://oma.media.fi/tekoaly-journalismissamme/">
1011Tekoäly journalismissamme</a></div>
1012		<div class="diks-column diks-column--span-2"><a class="diks-footer__main-link" href="https://oma.media.fi/sipoon-sanomat/">Asiakaspalvelu</a><a class="diks-footer__main-link" href="https://meks.fi/mainonta/alueet/etela-suomen-media/">Mediamyynti</a><a class="diks-footer__main-link" href="https://oma.media.fi/sipoon-sanomat/yhteystiedot/">Yhteystiedot</a></div>
1013	</div></div>
1014
1015					<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5"><h2 class="diks-footer__main-title">Mistä tänään puhutaan?</h2><form id="lianamailer-footer" class="diks-newsletter-form js-diks-recaptcha-newsletter-form" action="https://sisaltokirjeet.media.fi/account" method="post">
1016		<input type="hidden" name="join" value="759513"><input type="hidden" name="consent[]" value="2952-4-fi"><div class="diks-form__field-wrapper">
1017			<label class="diks-form__label" for="email">Sähköpostiosoite</label>
1018			<input class="diks-form__field" type="email" name="email" id="lianamailer-footer-email" size="30" value="">
1019		</div>
1020		<div class="diks-form__field-wrapper">
1021			<input class="diks-form__submit g-recaptcha" type="submit" data-sitekey="6Lfmg9UZAAAAAORf4dzYH7iNb-xFbjh-D45PEgqq" data-callback="onSubmitFooter" value="Tilaa uutiskirje">
1022		</div>
1023	</form></div>
1024
1025					<div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5">
1026						<h2 class="diks-footer__main-title">Sovellus</h2><p>Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston. Asenna sovellus laitteesi sovelluskaupasta.</p><div class="diks-footer__main-app-image-wrapper">
1027					<a class="diks-apps__app-link diks-hide-on-android" href="https://apps.apple.com/fi/app/sipoon-sanomat/id6740268452"><img class="diks-apps__app-image" src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/default/appstore-badge.svg" loading="lazy" alt="Lataa sovellus App Storesta"></a>
1028					<a class="diks-apps__app-link diks-hide-on-ios" href="https://play.google.com/store/apps/details?id=fi.media.sipoonsanomat"><img class="diks-apps__app-image" src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/default/google-play-badge.svg" loading="lazy" alt="Lataa sovellus Google Play -kaupasta"></a>
1029				</div>
1030		
1031						
1032					</div>
1033				</div>
1034			</div><div class="diks-footer__bottom">
1035				<div class="diks-footer__bottom-row"><div class="diks-footer__bottom-logo-wrapper"><a href="https://www.keskisuomalainen.com/"><img class="diks-footer__bottom-logo" src="https://a.sipoonsanomat.fi/styles/2efe7af9/images/logos/keskisuomalainen-sign.svg" loading="lazy" alt="Keskisuomalainen Oyj"></a></div><span>Kuulumme Mediakonserni Keskisuomalaiseen</span></div>
1036				<div class="diks-footer__bottom-link-farm-wrapper">
1037			<p><a class='diks-footer__bottom-link-farm-item' href='https://www.aamuposti.fi/'>Aamuposti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.avecmedia.fi/'>Avec</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.esaimaa.fi/'>Etelä-Saimaa</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.ess.fi/'>Etelä-Suomen Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.forssanlehti.fi/'>Forssan Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.hankasalmensanomat.fi/'>Hankasalmen Sanomat </a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.heinavedenlehti.fi/'>Heinäveden Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.helsinginuutiset.fi/'>Helsingin Uutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.hameensanomat.fi/'>Hämeen Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.hameenlinnankaupunkiuutiset.fi/'>Hämeenlinnan Kaupunkiuutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.iisalmensanomat.fi/'>Iisalmen Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.itahame.fi/'>Itä-Häme</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.ita-savo.fi/'>Itä-Savo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.joroistenlehti.fi/'>Joroisten Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.juvanlehti.fi/'>Juvan Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.kaakonkulma.fi/'>Kaakonkulma</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.kangasniemenlehti.fi/'>Kangasniemen Kunnallislehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.karjalainen.fi/'>Karjalainen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.heili.fi/'>Karjalan Heili</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.karkkilalainen.fi/'>Karkkilalainen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.keski-hame.fi/'>Keski-Häme</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.keski-uusimaa.fi/'>Keski-Uusimaa</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.keskilaakso.fi/'>Keskilaakso</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.ksml.fi/'>Keskisuomalainen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.koillis-savo.fi/'>Koillis-Savo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.kouvolansanomat.fi/'>Kouvolan Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.kymensanomat.fi/'>Kymen Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lappeenrannanuutiset.fi/'>Lappeenrannan Uutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.laukaa-konnevesi.fi/'>Laukaa-Konnevesi</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lieksanlehti.fi/'>Lieksan Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lopenlehti.fi/'>Lopen Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.loviisansanomat.fi/'>Loviisan Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.luumaenlehti.fi/'>Luumäen Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lansisaimaa.fi/'>Länsi-Saimaan Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lansi-savo.fi/'>Länsi-Savo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lansi-uusimaa.fi/'>Länsi-Uusimaa</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.lansivayla.fi/'>Länsiväylä</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.mattijaliisa.fi/'>Matti ja Liisa</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.meksi.fi/'>Meksi Urheilumedia</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.miilu.fi/'>Miilu</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.mikkelinkaupunkilehti.fi/'>Mikkelin Kaupunkilehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.mantsalanuutiset.fi/'>Mäntsälän Uutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.aamuposti.fi/aihe/Nurmij%C3%A4rvi'>Nurmijärven Uutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.outokummunseutu.fi/'>Outokummun Seutu</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.joutsenolehti.fi/'>Paikallislehti Joutseno</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.prsanomat.fi/'>Parikkalan-Rautjärven Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pernionseudunlehti.fi/'>Perniönseudun Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pieksamaenlehti.fi/'>Pieksämäen Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pielavesi-keitele.fi/'>Pielavesi-Keitele</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pielisjokiseutu.fi/'>Pielisjokiseutu</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pitajalainen.fi/'>Pitäjäläinen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pitajanuutiset.fi/'>Pitäjänuutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pogostansanomat.fi/'>Pogostan Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.puruvesi.net/'>Puruvesi</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.pyhtaanlehti.fi/'>Pyhtäänlehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.salonjokilaakso.fi/'>Salonjokilaakso</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.sampolehti.fi/'>Sampo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.savonsanomat.fi/'>Savon Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.sinunsavo.fi/'>Sinun Savo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.sisa-savolehti.fi/'>Sisä-Savo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.sisasuomenlehti.fi/'>Sisä-Suomen Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.soisalonseutu.fi/'>Soisalon Seutu</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.sjl.fi/'>Suur-Jyväskylän Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.tamperelainen.fi/'>Tamperelainen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.tollotin.fi/'>Töllötin</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.uusimaa.fi/'>Uusimaa</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.uutis-jousi.fi/'>Uutis-Jousi</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.uutisvuoksi.fi/'>Uutisvuoksi</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.vantaansanomat.fi/'>Vantaan Sanomat</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.vihdinuutiset.fi/'>Vihdin Uutiset</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.viikkosavo.fi/'>Viikkosavo</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.viispiikkinen.fi/'>
1037Viispiikkinen</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.viitasaarenseutu.fi/'>Viitasaaren Seutu</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.warkaudenlehti.fi/'>Warkauden Lehti</a> &bull; <a class='diks-footer__bottom-link-farm-item' href='https://www.ylakarjala.fi/'>Ylä-Karjala</a></p><p>Kaikki sisällöt voidaan julkaista kaikissa Mediakonserni Keskisuomalaisen medioissa.</p>
1038		</div>
1039			</div></div>
1040</footer>
1041
1042		
1043					
1043<script>
1044	if (!DOMTokenList.prototype.replace) {
1045		// IE Polyfill
1046		DOMTokenList.prototype.replace = function (a, b) {
1047			if (this.contains(a)) {
1048					this.add(b);
1049					this.remove(a);
1050					return true;
1051			}
1052			return false;
1053		}
1054	}
1055
1056	document.querySelector('.diks-no-js').classList.replace('diks-no-js', 'diks-js');
1057
1058	// User agent sniffing is not reliable and it's going away.
1059	// Use only to sprinkle a little bit of progressive enhancement on top.
1060	// Dear Apple, stop lying, iPad on iOS 13 is not a Mac. You're turning into 90s Microsoft.
1061	var userAgent = navigator.userAgent || navigator.vendor || window.opera;
1062	if (/android/i.test(userAgent)) {
1063		document.querySelector('html').classList.add('diks-user-agent--android');
1064	} else if (/iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream) {
1065		document.querySelector('html').classList.add('diks-user-agent--ios');
1066	} else if (/macintosh/i.test(userAgent) && navigator.maxTouchPoints > 1) {
1067		document.querySelector('html').classList.add('diks-user-agent--ios');
1068	}
1069</script>
1069
1070
1071<script>
1072	// Fix forEach for IE
1073	if (window.NodeList && !NodeList.prototype.forEach) {
1074		NodeList.prototype.forEach = Array.prototype.forEach;
1075	}
1076
1077	// Element.closest() needs a polyfill for older browsers.
1078	// While we only need the closest() functionality for mobile browsers,
1079	// we don't want the code to fail even on old desktop browsers.
1080	// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
1081	// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility
1082	if (!Element.prototype.matches) {
1083		Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
1084	}
1085
1086	if (!Element.prototype.closest) {
1087		Element.prototype.closest = function(s) {
1088			var el = this;
1089
1090			do {
1091				if (el.matches(s)) return el;
1092				el = el.parentElement || el.parentNode;
1093			} while (el !== null && el.nodeType === 1);
1094			return null;
1095		};
1096	}
1097
1098	function setAriaExpanded(toggler, ariaExpandedValue) {
1099		// Set aria-expanded attribute of dropdown toggler
1100		// If the toggler contains a button, set the aria-expanded attribute for the button instead
1101		if ( toggler.querySelector('button') != null ) {
1102			toggler.querySelector('button').setAttribute('aria-expanded', ariaExpandedValue);
1103		}
1104		else {
1105			toggler.setAttribute('aria-expanded', ariaExpandedValue);
1106		}
1107	}
1108
1109	function toggleElement(target, toggleClass, toggler) {
1110		if (toggleClass) {
1111			var isOpenClass = toggleClass + '--is-open';
1112			var isClosedClass = toggleClass + '--is-closed';
1113
1114			if (target.classList.contains(isOpenClass)) {
1115				// Close this toggle
1116				target.classList.remove(isOpenClass);
1117				target.classList.add(isClosedClass);
1118
1119				// Set aria-expanded to false for the toggler
1120				setAriaExpanded(toggler, 'false');
1121
1122			} else if (target.classList.contains(isClosedClass)) {
1123				// Open this toggle
1124				target.classList.remove(isClosedClass);
1125				target.classList.add(isOpenClass);
1126
1127				// Set aria-expanded to true for the toggler
1128				setAriaExpanded(toggler, 'true');
1129			} else {
1130				// Open this toggle as a fallback
1131				target.classList.add(isOpenClass);
1132
1133				// Set aria-expanded to true for the toggler
1134				setAriaExpanded(toggler, 'true');
1135			}
1136		} else {
1137			if (window.getComputedStyle(target).display !== 'none') {
1138				target.style.display = 'none';
1139			} else {
1140				target.style.display = 'block';
1141			}
1142		}
1143	};
1144
1145	document.querySelectorAll('.js-diks-toggler').forEach(function(toggler) {
1146		var toggleId = toggler.getAttribute('data-diks-toggle');
1147		var target = document.getElementById(toggleId);
1148		var eventListenerAttached = toggler.getAttribute('data-diks-event-click');
1149
1150		if (target && !eventListenerAttached) {
1151
1152			// Set aria-controls of toggler
1153			if ( toggler.querySelector('button') != null ) {
1154				toggler.querySelector('button').setAttribute('aria-controls', toggleId);
1155			}
1156			else {
1157				toggler.setAttribute('aria-controls', toggleId);
1158			}
1159
1160			toggler.addEventListener('click', function(e) {
1161				e.preventDefault();
1162
1163				var toggleClass = toggler.getAttribute('data-diks-toggle-class');
1164
1165				if (webShareAPIEnabled(toggleId)) {
1166					share();
1167				} else {
1168					toggleElement(target, toggleClass, toggler);
1169				}
1170			});
1171
1172			toggler.setAttribute('data-diks-event-click', true);
1173		}
1174	});
1175
1176	// Web Share and Clipboard API capabilities
1177
1178	function webShareAPIEnabled(toggleId) {
1179		const webShareAPIEnabled = true;
1180		const webShareAPIDropdownShareIds = ["jaa","jakopainikkeet"];
1181		const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
1182
1183		return webShareAPIEnabled && webShareAPIDropdownShareIds.includes(toggleId) && isMobileDevice && navigator.share ? true : false;
1184	}
1185
1186	function share() {
1187		const metaTitleElement = document.querySelector('meta[property="og:title"]');
1188		const metaDescriptionElement = document.querySelector('meta[name="description"]');
1189		const metaUrlElement = document.querySelector('meta[property="og:url"]');
1190		let title = '';
1191		let description = '';
1192		let url = document.location.href;
1193
1194		if (metaTitleElement && metaTitleElement.content) {
1195			title = metaTitleElement.content;
1196		}
1197
1198		if (metaDescriptionElement && metaDescriptionElement.content) {
1199			description = metaDescriptionElement.content;
1200		}
1201
1202		if (metaUrlElement && metaUrlElement.content) {
1203			url = metaUrlElement.content;
1204		}
1205
1206		navigator.share({
1207			title: title,
1208			text: description,
1209			url: url
1210		});
1211	}
1212
1213	document.querySelectorAll('.js-diks-share-clipboard').forEach(function(element) {
1214		element.addEventListener('click', function(e) {
1215			e.preventDefault();
1216
1217			let url = document.location.href;
1218			const metaUrlElement = document.querySelector('meta[property="og:url"]');
1219
1220			if (metaUrlElement && metaUrlElement.content) {
1221				url = metaUrlElement.content;
1222			}
1223
1224			// Copy URL to clipboard
1225			navigator.clipboard.writeText(url).then(function () {
1226				// Copying URL to clipboard succeeded
1227				const dropdownId = element.getAttribute('data-diks-dropdown-id');
1228				// Find closest dropdown toggler
1229				let dropdownToggler = element.closest('.diks-dropdown').querySelector('.js-diks-toggler');
1230
1231				if (dropdownId) {
1232					const dropdownElement = document.getElementById(dropdownId);
1233
1234					if (dropdownElement) {
1235						// Close currently open dropdown
1236						toggleElement(dropdownElement, 'diks-dropdown__content', dropdownToggler);
1237					}
1238
1239					// Show link copied notification text
1240					const notificationTextWrapperDiv = document.createElement('div');
1241					const notificationTextDiv = document.createElement('div');
1242					const notificationText = document.createTextNode('Linkki kopioitu leikepöydälle');
1243
1244					notificationTextDiv.classList.add('diks-dropdown__notification-text');
1245					notificationTextDiv.appendChild(notificationText);
1246					notificationTextWrapperDiv.classList.add('diks-dropdown__notification-text-wrapper');
1247					notificationTextWrapperDiv.appendChild(notificationTextDiv);
1248					dropdownElement.parentNode.insertBefore(notificationTextWrapperDiv, null);
1249
1250					setTimeout(function () {
1251						notificationTextWrapperDiv.remove();
1252					}, 5000);
1253				}
1254			});
1255		});
1256	});
1257
1258        const initContentBlockToggleButtons = () => {
1259        const toggleContainers = document.querySelectorAll('[data-diks-init="toggle"]');
1260        toggleContainers.forEach(container => {
1261            const toggleButton = container.querySelector('.diks-toggle-button');
1262            const toggleContent = container.querySelector('.diks-toggle-content-container');
1263            if (toggleButton && toggleContent) {
1264                toggleButton.addEventListener('click', () => {
1265                    toggleElement(toggleContent, 'diks-toggle', toggleButton);
1266                });
1267            }
1268        });
1269    };
1270    document.addEventListener('DOMContentLoaded', () => {
1271        initContentBlockToggleButtons();
1272    });
1273
1274</script>
1274
1275
1276<script>
1277	const useDragThreshold = true;
1278
1279	// Horizontally scrollable & draggable navigation
1280	class HorizontalScrollDragger {
1281		constructor(element) {
1282			this.slider = typeof element === 'string' ? document.querySelector(element) : element instanceof Element ? element : null;
1283			if (this.slider === null) return console.error('HorizontalScrollDragger: Element not found');
1284
1285			this.isDown = false;
1286			this.preventClick = false;
1287			this.startX;
1288			this.scrollLeft;
1289
1290			this.dragThreshold = 5;
1291			this.dragSensitivity = 1;
1292			this.dragged = false;
1293
1294			this.init();
1295		}
1296
1297		init() {
1298			this.slider.addEventListener('mousedown', (e) => this.handleMouseDown(e));
1299			this.slider.addEventListener('mouseleave', () => this.handleMouseLeave());
1300			this.slider.addEventListener('mouseup', () => this.handleMouseUp());
1301			this.slider.addEventListener('mousemove', (e) => this.handleMouseMove(e));
1302			this.slider.addEventListener('click', (e) => this.handleClick(e));
1303		}
1304
1305		handleMouseDown(e) {
1306			this.isDown = true;
1307			this.slider.classList.add('diks-navigation--draggable-active');
1308			this.startX = e.pageX - this.slider.offsetLeft;
1309			this.scrollLeft = this.slider.scrollLeft;
1310			this.preventClick = false;
1311		}
1312
1313		handleMouseLeave() {
1314			this.isDown = false;
1315			this.slider.classList.remove('diks-navigation--draggable-active');
1316		}
1317
1318		handleMouseUp() {
1319			this.isDown = false;
1320			this.slider.classList.remove('diks-navigation--draggable-active');
1321		}
1322
1323		handleMouseMove(e) {
1324			if (!this.isDown) return;
1325
1326			if ( useDragThreshold == true ) {
1327				const xWithThreshold = e.pageX - this.slider.offsetLeft;
1328				const delta = xWithThreshold - this.startX;
1329
1330				// If not yet dragging, check threshold
1331				if (!this.dragged && Math.abs(delta) > this.dragThreshold) {
1332					this.dragged = true;
1333					this.preventClick = true;
1334
1335					// Reset baseline so scrolling starts smoothly from here
1336					this.startX = xWithThreshold;
1337					this.scrollLeft = this.slider.scrollLeft;
1338				}
1339
1340				if (this.dragged) {
1341					e.preventDefault();
1342					const walkWithThreshold = (xWithThreshold - this.startX) * this.dragSensitivity; // adjust sensitivity
1343					this.slider.scrollLeft = this.scrollLeft - walkWithThreshold;
1344				}
1345			}
1346			else {
1347				e.preventDefault();
1348				const x = e.pageX - this.slider.offsetLeft;
1349				const walk = (x - this.startX) * this.dragSensitivity; // adjust sensitivity
1350				this.slider.scrollLeft = this.scrollLeft - walk;
1351				this.preventClick = true;
1352			}
1353
1354		}
1355
1356		handleClick(e) {
1357			if ( useDragThreshold == true && this.preventClick && this.dragged ) {
1358				e.preventDefault();
1359			}
1360			else if ( useDragThreshold == false && this.preventClick) {
1361				e.preventDefault();
1362			}
1363		}
1364	}
1365
1366	// Set the draggable navs (multiple) to handle their scrollbars
1367	let scrollableNavs = document.querySelectorAll('.diks-navigation--draggable');
1368
1369	// Make draggable navigation draggable
1370	if ( scrollableNavs ) {
1371		scrollableNavs.forEach(function(element) {
1372			new HorizontalScrollDragger(element);
1373		});
1374	}
1375
1376
1377	// Handle has-scrollbars class adding and removing
1378	function handleScrollableNavScrollbars(scrollableNavElement) {
1379		// If scrollable area is wider (scrollWidth) than what's visible (clientWidth) the element has scrollbars
1380		if ( scrollableNavElement.scrollWidth > scrollableNavElement.clientWidth ) {
1381			scrollableNavElement.classList.add('diks-navigation--draggable-has-scrollbars');
1382			scrollableNavElement.parentElement.classList.add('diks-navigation-wrapper--has-scrollbars');
1383		}
1384		// Remove the has-scrollbars class if it exists but shouldn't (element does not have scrollbars)
1385		else if ( scrollableNavElement.classList.contains('diks-navigation--draggable-has-scrollbars') ) {
1386			scrollableNavElement.classList.remove('diks-navigation--draggable-has-scrollbars');
1387			scrollableNavElement.parentElement.classList.remove('diks-navigation-wrapper--has-scrollbars');
1388		}
1389	}
1390
1391	// If scrollable nav exists add (or remove) necessary classes
1392	// "DOMContentLoaded" does not wait for styles to load and styles affect the size of the scrollable nav directly so we have to use "load" instead
1393	window.addEventListener('load', (event) => {
1394		if ( scrollableNavs ) {
1395			scrollableNavs.forEach(function(element) {
1396				handleScrollableNavScrollbars(element);
1397			});
1398		}
1399	});
1400
1401	// Check if scrollable nav has scrollbar
1402	window.addEventListener('resize', function(event){
1403		if ( scrollableNavs ) {
1404			scrollableNavs.forEach(function(element) {
1405				handleScrollableNavScrollbars(element);
1406			});
1407		}
1408	});
1409</script>
1409
1410
1411<script>
1412	// Back button handling
1413	document.querySelectorAll('a.js-diks-back-button').forEach(function(item) {
1414		var referrerIsSameDomain = false;
1415		// Check if referrer is found as referrer isn't always available (browser, tab, window, bookmark, privacy).
1416		if (typeof(document.referrer) === 'string' && document.referrer.length > 0) {
1417			// Set referrerIsSameDomain to true if referrer is in the same domain as current location hostname and referrer is not the same page as current page (window.location.href)
1418			if ( document.referrer.includes(document.location.hostname) && document.referrer != window.location.href ) {
1419				referrerIsSameDomain = true;
1420			}
1421		}
1422
1423		// Overwrite link with history.go, as it also remembers scroll position but only if referrer is the same domain as current location hostname
1424		if (history.length > 1 && referrerIsSameDomain == true) {
1425			// Set referrer as back button href to enable visual cue & opening to a new window
1426			item.setAttribute('href', document.referrer);
1427
1428			// Set back button text
1429			item.querySelector('.diks-header__cta-text').innerHTML = "Takaisin";
1430			
1431			var stepsToGoBack = -1;
1432
1433			item.addEventListener('click', function(e) {
1434				e.preventDefault();
1435				history.go(stepsToGoBack);
1436			});
1437		}
1438	});
1439</script>
1439
1440
1441			<link rel="stylesheet" href="/theme/css/includes/lightgallery/css/lightgallery-bundle.min.css">
1442	<style>.lg-sub-html { background-color: rgba(0,0,0, .6); }</style>
1443	
1443<script src="/theme/css/includes/lightgallery/lightgallery.min.js"></script>
1443
1444	
1444<script src="/theme/css/includes/lightgallery/plugins/autoplay/lg-autoplay.min.js"></script>
1444
1445	
1445<script src="/theme/css/includes/lightgallery/plugins/fullscreen/lg-fullscreen.min.js"></script>
1445
1446	
1446<script src="/theme/css/includes/lightgallery/plugins/thumbnail/lg-thumbnail.min.js"></script>
1446
1447	
1447<script src="/theme/css/includes/lightgallery/plugins/zoom/lg-zoom.min.js"></script>
1447
1448	
1448<script>
1449		// lightGallery
1450		// Separate gallery for every .js-lightgallery
1451		// Gallery items come from .js-lightgallery .js-lightgallery__link
1452		// https://www.lightgalleryjs.com/docs/getting-started/
1453		document.querySelectorAll('.js-diks-lightgallery').forEach(function(gallery) {
1454			var galleryImageLinks = gallery.getElementsByClassName('diks-gallery__link');
1455
1456			// Thumbnails come from img inside the links, unless links specify data-thumbnail
1457			var thumbnailSource = (galleryImageLinks[0].hasAttribute('data-thumbnail')) ? ('data-thumbnail') : (false);
1458
1459			// Adjust certain settings depending on whether the gallery has one or more images
1460			var galleryHasMultipleImages = (galleryImageLinks.length > 1 ? true : false);
1461
1462			// Initialize
1463			lightGallery(gallery, {
1464				autoplay: galleryHasMultipleImages,
1465				counter: galleryHasMultipleImages,
1466				download: false,
1467				exThumbImage: thumbnailSource,
1468				hideControlOnEnd: true,
1469				licenseKey: "96BAAD7E-3BF04397-BBB55AE3-6D5A2C0B",
1470				loop: false,
1471				plugins: [lgAutoplay, lgFullscreen, lgThumbnail, lgZoom],
1472				selector: '.diks-gallery__link',
1473				mobileSettings: {
1474					controls: true,
1475					showCloseIcon: true
1476				},
1477				strings: {
1478					closeGallery: 'Sulje galleria',
1479					toggleMaximize: 'Maksimointi',
1480					previousSlide: 'Edellinen',
1481					nextSlide: 'Seuraava',
1482					download: 'Lataa',
1483					playVideo: 'Katso video',
1484					mediaLoadingFailed: 'Sisällön lataus epäonnistui',
1485				},
1486				autoplayPluginStrings: {
1487					toggleAutoplay: 'Automaattinen toisto'
1488				},
1489				fullscreenPluginStrings: {
1490					toggleFullscreen: 'Kokoruututila'
1491				},
1492				thumbnailPluginStrings: {
1493					toggleThumbnails: 'Pikkukuvat'
1494				},
1495				zoomPluginStrings: {
1496					zoomIn: 'Suurenna',
1497					zoomOut: 'Pienennä',
1498					viewActualSize: 'Näytä täysikokoisena'
1499				}
1500			});
1501
1502			// After closing LightGallery return focus to the image link that opened the gallery 
1503			gallery.addEventListener('lgAfterClose', () => {
1504				galleryImageLinks[0].focus();
1505			});
1506
1507		});
1508
1509	</script>
1509
1510
1511<script>
1512	function loadScript(url, callback) {
1513		var script = document.createElement("script");
1514		script.type = "text/javascript";
1515		if (script.readyState) {  // IE
1516			script.onreadystatechange = function() {
1517				if (script.readyState === "loaded" || script.readyState === "complete") {
1518					script.onreadystatechange = null;
1519					callback();
1520				}
1521			};
1522		} else {  // Others
1523			script.onload = function() {
1524				callback();
1525			};
1526		}
1527		script.src = url;
1528		document.getElementsByTagName("head")[0].appendChild(script);
1529	}
1530	function checkAudioElements() {
1531		// load audioplayer script only when audio elements are found
1532		if (document.querySelector(".init-audio-player")) {
1533			loadScript("https://a.sipoonsanomat.fi/styles/2efe7af9/js/audioplayer/diks-audioplayer.min.js", function() {
1534				DiksAudioPlayer.init({
1535					selector: '.init-audio-player',
1536					stopOthersOnPlay: true,
1537					enableKeystrokes: true
1538				});
1539			});
1540		}
1541	}
1542	window.onload = (event) => {
1543		checkAudioElements();
1544	};
1545</script>
1545<script>
1546    // ================================================================
1547    // Unified Content Block Component
1548    // ================================================================
1549
1550    const DiksContentBlock = (() => {
1551        // Private utility functions
1552        const utils = {
1553            setCookie: (name, value, days = 30) => {
1554                const expires = new Date();
1555                expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
1556                document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/`;
1557            },
1558
1559            getCookie: (name) => {
1560                const value = `; ${document.cookie}`;
1561                const parts = value.split(`; ${name}=`);
1562                if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift());
1563                return null;
1564            },
1565
1566            renderArticleCard: (article) => {
1567                let mainImage = article.mainImage;
1568
1569                // For ContentPackage: if mainImage is empty, get from first story in teaserStories
1570                if (article.type === 'ContentPackage' && (!mainImage || mainImage.length === 0)) {
1571                    if (article.teaserStories && article.teaserStories.length > 0) {
1572                        // Find first teaser story with a mainImage
1573                        for (const teaserStory of article.teaserStories) {
1574                            if (teaserStory.content &&
1575                                teaserStory.content.mainImage &&
1576                                teaserStory.content.mainImage.length > 0) {
1577                                mainImage = teaserStory.content.mainImage;
1578                                break;
1579                            }
1580                        }
1581                    }
1582                }
1583
1584                let imageHtml = '';
1585                if (mainImage && mainImage.length > 0) {
1586                    const imageFields = mainImage[0].content.fields;
1587                    const src = imageFields.landscape_720.href_full;
1588                    const srcset = `
1589                        ${imageFields.landscape_240.href_full} 240w,
1590                        ${imageFields.landscape_480.href_full} 480w,
1591                        ${imageFields.landscape_720.href_full} 720w,
1592                        ${imageFields.landscape_960.href_full} 960w
1593                    `;
1594                    imageHtml = `
1595                        <div class="diks-card__image-wrapper">
1596                            <img class="diks-card__image"
1597                                 src="${src}"
1598                                 loading="lazy"
1599                                 sizes="(max-width: 504px) 480px, (max-width: 1279px) 720px, 960px"
1600                                 srcset="${srcset}"
1601                                 decoding="async"
1602                                 alt="${article.headline}"
1603                                 pinger-seen="true">
1604                        </div>
1605                    `;
1606                }
1607
1608                const fullHeadline = article.headlinePrefix
1609                    ? `<span class="diks-ui-accent">${article.headlinePrefix} | </span>${article.headline}`
1610                    : article.headline;
1611
1612                const publishedDate = new Date(article.published).toLocaleString('fi-FI', {
1613                    day: 'numeric',
1614                    month: 'numeric',
1615                    year: 'numeric',
1616                    hour: 'numeric',
1617                    minute: 'numeric'
1618                });
1619
1620                return `
1621                    <article class="diks-card diks-card--size-s">
1622                        <div class="diks-card__main-wrapper">
1623                            ${imageHtml}
1624                            <div class="diks-card__text-wrapper">
1625                                <div class="diks-card__text-inner-wrapper">
1626                                    <h2 class="diks-card__title">
1627                                        <a class="diks-card__link" href="${article.href}">${fullHeadline}</a>
1628                                    </h2>
1629                                    <div class="diks-card__meta-wrapper">
1630                                        <div class="diks-meta">
1631                                            <div class="diks-date">
1632                                                <time class="diks-date__published" datetime="${article.published}">${publishedDate}</time>
1633                                            </div>
1634                                        </div>
1635                                    </div>
1636                                </div>
1637                            </div>
1638                        </div>
1639                    </article>
1640                `;
1641            },
1642
1643            getComponentType: (containerId) => {
1644                if (containerId.startsWith('diks-content-block-search-')) return 'search';
1645                if (containerId.startsWith('diks-content-block-aggregator-')) return 'aggregator';
1646                return null;
1647            },
1648
1649            getBlockId: (containerId, type) => {
1650                if (type === 'search') return containerId.replace('diks-content-block-search-', '');
1651                if (type === 'aggregator') return containerId.replace('diks-content-block-aggregator-', '');
1652                return containerId;
1653            },
1654
1655            getResultsId: (blockId, type) => {
1656                if (type === 'search') return `diks-search-results-${blockId}`;
1657                if (type === 'aggregator') return `diks-results-${blockId}`;
1658                return null;
1659            }
1660        };
1661
1662        // Build query parameters based on component type and filters
1663        const buildQueryParams = (containerId) => {
1664            const container = document.getElementById(containerId);
1665            const type = utils.getComponentType(containerId);
1666            const blockId = utils.getBlockId(containerId, type);
1667
1668            const params = new URLSearchParams({
1669                type: container.dataset.queryType || 'story',
1670                size: container.dataset.maxResults || 20
1671            });
1672
1673            if (type === 'search') {
1674                // Search-specific parameters
1675                const defaultSort = container.dataset.sort;
1676                const defaultPaywall = container.dataset.paywall;
1677                const defaultStoryTypes = container.dataset.storyTypes;
1678                const defaultTopics = container.dataset.topics;
1679                const defaultAdvertisers = container.dataset.advertisers;
1680                const dateRangeType = container.dataset.dateRangeType;
1681
1682                // Sort
1683                if (defaultSort && defaultSort !== '*') {
1684                    params.append('sort', defaultSort);
1685                }
1686
1687                // Paywall
1688                const paywallSelect = document.getElementById(`diks-search-paywall-${blockId}`);
1689                if (paywallSelect && paywallSelect.value) {
1690                    params.append('paywall', paywallSelect.value);
1691                } else if (defaultPaywall && defaultPaywall !== '*') {
1692                    params.append('paywall', defaultPaywall);
1693                }
1694
1695                // Story types
1696                let storyTypesValue = defaultStoryTypes;
1697                const storyTypesSelect = document.getElementById(`diks-search-story-types-${blockId}`);
1698                if (storyTypesSelect) {
1699                    const selectedOptions = Array.from(storyTypesSelect.selectedOptions).map(opt => opt.value);
1700                    if (selectedOptions.length > 0) {
1701                        storyTypesValue = selectedOptions.join(',');
1702                    }
1703                }
1704                if (storyTypesValue) {
1705                    params.append('storyTypes', storyTypesValue);
1706                }
1707
1708                // Topics
1709                if (defaultTopics) {
1710                    params.append('topics', defaultTopics);
1711                    const topicsOperator = container.dataset.topicsOperator || 'OR';
1712                    params.append('topicsOperator', topicsOperator);
1713                }
1714
1715                // Advertisers
1716                if (defaultAdvertisers) {
1717                    params.append('advertisers', defaultAdvertisers);
1718                    const advertisersOperator = container.dataset.advertisersOperator || 'OR';
1719                    params.append('advertisersOperator', advertisersOperator);
1720                }
1721
1722                // Date ranges
1723                const fromDateInput = document.getElementById(`diks-search-from-date-${blockId}`);
1724                const toDateInput = document.getElementById(`diks-search-to-date-${blockId}`);
1725                const monthInput = document.getElementById(`diks-search-month-${blockId}`);
1726
1727                if (dateRangeType === 'byMonth' && monthInput && monthInput.value) {
1728                    const [year, month] = monthInput.value.split('-').map(Number);
1729                    const fromDate = new Date(year, month - 1, 1, 0, 0, 0, 0);
1730                    const toDate = new Date(year, month, 0, 23, 59, 59, 999);
1731                    params.append('fromDate', fromDate.toISOString().split('.')[0] + 'Z');
1732                    params.append('toDate', toDate.toISOString().split('.')[0] + 'Z');
1733                } else {
1734                    if (fromDateInput && fromDateInput.value) {
1735                        const fromDate = new Date(fromDateInput.value);
1736                        fromDate.setHours(0, 0, 0, 0);
1737                        params.append('fromDate', fromDate.toISOString().split('.')[0] + 'Z');
1738                    }
1739                    if (toDateInput && toDateInput.value) {
1740                        const toDate = new Date(toDateInput.value);
1741                        toDate.setHours(23, 59, 59, 999);
1742                        params.append('toDate', toDate.toISOString().split('.')[0] + 'Z');
1743                    }
1744                }
1745            } else if (type === 'aggregator') {
1746                // Aggregator-specific parameters
1747                const selectedTopic = container.dataset.selectedTopic;
1748                if (selectedTopic) {
1749                    params.append('topics', selectedTopic);
1750                }
1751            }
1752
1753            return params;
1754        };
1755
1756        // Main fetch content function
1757        const fetchContent = async (containerId) => {
1758            const container = document.getElementById(containerId);
1759            const type = utils.getComponentType(containerId);
1760            const blockId = utils.getBlockId(containerId, type);
1761            const resultsId = utils.getResultsId(blockId, type);
1762            const resultsDiv = document.getElementById(resultsId);
1763
1764            if (!container || !resultsDiv) {
1765                console.error(`Content block container or results div not found: ${containerId}`);
1766                return;
1767            }
1768
1769            try {
1770                // Show loading state
1771                const loadingMessage = type === 'search'
1772                    ? '<p class="diks-content-block-search--loading">Ladataan...</p>'
1773                    : '<p class="diks-content-block-aggregator--loading">Ladataan...</p>';
1774                resultsDiv.innerHTML = loadingMessage;
1775
1776                // Build query parameters
1777                const params = buildQueryParams(containerId);
1778                const apiUrl = container.dataset.apiUrl || '/.content/items';
1779
1780                // Fetch data
1781                const response = await fetch(`${apiUrl}?${params.toString()}`, {
1782                    method: 'GET'
1783                });
1784
1785                if (!response.ok) {
1786                    throw new Error('Verkkovirhe.');
1787                }
1788
1789                const data = await response.json();
1790
1791                // Render results
1792                let html = '';
1793                if (data.items && data.items.length > 0) {
1794                    data.items.forEach(article => {
1795                        html += utils.renderArticleCard(article);
1796                    });
1797                } else {
1798                    const noResultsMessage = type === 'search'
1799                        ? '<p class="diks-content-block-search--no-results">Ei hakutuloksia.</p>'
1800                        : '<p>Ei sisältöä.</p>';
1801                    html = noResultsMessage;
1802                }
1803
1804                resultsDiv.innerHTML = html;
1805            } catch (error) {
1806                const errorMessage = type === 'search'
1807                    ? `<p class="diks-content-block-search--error">Virhe: ${error.message}</p>`
1808                    : `<p class="error">Error: ${error.message}</p>`;
1809                resultsDiv.innerHTML = errorMessage;
1810            }
1811        };
1812
1813        // Initialize search component
1814        const initializeSearch = (containerId) => {
1815            const container = document.getElementById(containerId);
1816            const blockId = utils.getBlockId(containerId, 'search');
1817            const dateRangeType = container.dataset.dateRangeType;
1818
1819            // Get UI elements
1820            const searchButton = document.getElementById(`diks-search-button-${blockId}`);
1821            const fromDateInput = document.getElementById(`diks-search-from-date-${blockId}`);
1822            const toDateInput = document.getElementById(`diks-search-to-date-${blockId}`);
1823            const monthInput = document.getElementById(`diks-search-month-${blockId}`);
1824
1825            // Set current month as default for byMonth type
1826            if (dateRangeType === 'byMonth' && monthInput) {
1827                const now = new Date();
1828                const year = now.getFullYear();
1829                const month = String(now.getMonth() + 1).padStart(2, '0');
1830                monthInput.value = `${year}-${month}`;
1831
1832                // Auto-trigger search on month change
1833                monthInput.addEventListener('change', () => fetchContent(containerId));
1834            }
1835
1836            // Search button click handler
1837            if (searchButton) {
1838                searchButton.addEventListener('click', () => fetchContent(containerId));
1839            }
1840
1841            // Enter key support
1842            [fromDateInput, toDateInput, monthInput].forEach(input => {
1843                if (input) {
1844                    input.addEventListener('keypress', (e) => {
1845                        if (e.key === 'Enter') fetchContent(containerId);
1846                    });
1847                }
1848            });
1849
1850            // Initial search
1851            fetchContent(containerId);
1852        };
1853
1854        // Initialize aggregator component
1855        const initializeAggregator = (containerId) => {
1856            const container = document.getElementById(containerId);
1857            const blockId = utils.getBlockId(containerId, 'aggregator');
1858            const topicLabels = JSON.parse(container.dataset.topicLabels || '{}');
1859            const cookieName = `selectedTopic_${blockId}`;
1860
1861            const listId = `diks-topic-list-${blockId}`;
1862            const labelId = `diks-selected-topic-label-${blockId}`;
1863            const toggleId = `diks-toggle-button-${blockId}`;
1864            const listContainerId = `diks-toggle-area-${blockId}`;
1865
1866            const topicItems = document.querySelectorAll(`#${listId} .diks-topic-list__item`);
1867            const labelElement = document.getElementById(labelId);
1868
1869            // Update topic label display
1870            const updateTopicLabel = (topic) => {
1871                if (labelElement && topicLabels[topic]) {
1872                    labelElement.textContent = topicLabels[topic];
1873                } else if (labelElement) {
1874                    labelElement.textContent = '';
1875                }
1876
1877                // Update active state
1878                topicItems.forEach(item => {
1879                    item.classList.toggle('diks-is-active', item.dataset.topic === topic);
1880                });
1881            };
1882
1883            // Handle single topic case
1884            if (Object.keys(topicLabels).length === 1) {
1885                const initialTopic = Object.keys(topicLabels)[0];
1886                container.dataset.selectedTopic = initialTopic;
1887                updateTopicLabel(initialTopic);
1888                fetchContent(containerId);
1889                return;
1890            }
1891
1892            // Handle multiple topics case
1893            if (topicItems.length > 0) {
1894                // Determine initial topic (cookie or first)
1895                const cookieTopic = utils.getCookie(cookieName);
1896                let initialTopic = topicItems[0].dataset.topic;
1897
1898                if (cookieTopic) {
1899                    const validTopic = Array.from(topicItems).some(item => item.dataset.topic === cookieTopic);
1900                    if (validTopic) {
1901                        initialTopic = cookieTopic;
1902                    }
1903                }
1904
1905                // Set up topic click handlers
1906                topicItems.forEach(item => {
1907                    item.addEventListener('click', () => {
1908                        const selectedTopic = item.dataset.topic;
1909                        container.dataset.selectedTopic = selectedTopic;
1910                        utils.setCookie(cookieName, selectedTopic);
1911                        updateTopicLabel(selectedTopic);
1912                        fetchContent(containerId);
1913
1914                        // Close toggle if open
1915                        const toggleButton = document.getElementById(toggleId);
1916                        const listContainer = document.getElementById(listContainerId);
1917                        if (toggleButton && listContainer) {
1918                            toggleButton.setAttribute('aria-expanded', 'false');
1919                            listContainer.classList.remove('diks-toggle--is-open');
1920                            listContainer.classList.add('diks-toggle--is-closed');
1921                            container.dataset.diksToggleState = 'closed';
1922                        }
1923                    });
1924                });
1925
1926                // Initial fetch
1927                container.dataset.selectedTopic = initialTopic;
1928                updateTopicLabel(initialTopic);
1929                fetchContent(containerId);
1930            }
1931        };
1932
1933        // Public API
1934        return {
1935            fetchContent,
1936            initialize: (containerId) => {
1937                const type = utils.getComponentType(containerId);
1938                if (type === 'search') {
1939                    initializeSearch(containerId);
1940                } else if (type === 'aggregator') {
1941                    initializeAggregator(containerId);
1942                }
1943            }
1944        };
1945    })();
1946
1947
1948    // ================================================================
1949    // Auto-initialize all content block components
1950    // ================================================================
1951
1952    document.addEventListener('DOMContentLoaded', () => {
1953        // Initialize all content block components (search + aggregator)
1954        const allContainers = document.querySelectorAll('[id^="diks-content-block-search-"], [id^="diks-content-block-aggregator-"]');
1955        allContainers.forEach(container => {
1956            DiksContentBlock.initialize(container.id);
1957        });
1958    });
1959</script>
vendor: 1 bytes, line 1959
1959
1960<script>
1961	// Service Worker
1962	if ('serviceWorker' in navigator) {
1963		window.addEventListener('load', function() {
1964			navigator.serviceWorker.register('/sw.js').then(
1965				function(registration) {
1966					console.log('PWA: Service worker registered to scope: ', registration.scope);
1967				},
1968				function(err) {
1969					console.error('PWA: Service worker failed to register with error: ', err);
1970				}
1971			);
1972		});
1973	}
1974
1975	// Show installation option, hide generic fallback instructions
1976	function pwaShowInstallationOption() {
1977		document.querySelectorAll('.js-diks-apps-pwa-installation').forEach(function(element) {
1978			element.style.display = 'block';
1979		});
1980		document.querySelectorAll('.js-diks-apps-pwa-instructions').forEach(function(element) {
1981			element.style.display = 'none';
1982		});
1983	}
1984
1985	let deferredPrompt;
1986	var dataLayer = window.dataLayer || [];
1987
1988	// Basic installation process
1989	window.addEventListener('beforeinstallprompt', (e) => {
1990		// Stash the event so it can be triggered later
1991		deferredPrompt = e;
1992
1993		const enablePrompt = 0;
1994
1995		if(!enablePrompt) {
1996			e.preventDefault();
1997		}
1998
1999		// Update the UI to notify the user they can install PWA
2000		pwaShowInstallationOption();
2001
2002		// Handle installation
2003		document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) {
2004			button.addEventListener('click', (e) => {
2005				// Show the prompt
2006				deferredPrompt.prompt();
2007
2008				// Wait for user to respond
2009				deferredPrompt.userChoice.then((choiceResult) => {
2010					if (choiceResult.outcome === 'accepted') {
2011						console.log('PWA: Installed (prompt)');
2012						dataLayer.push({
2013							'event': 'PWA.installation',
2014							'eventData': 'success'
2015						});
2016					} else {
2017						console.log('PWA: User dismissed installation prompt');
2018						dataLayer.push({
2019							'event': 'PWA.installation',
2020							'eventData': 'canceled'
2021						});
2022					}
2023					deferredPrompt = null;
2024				});
2025			});
2026		});
2027	});
2028
2029	// iOS installation process (show instructions modal)
2030	if (!navigator.standalone) {
2031		var userAgent = navigator.userAgent.toLowerCase();
2032		var iPhoneUser = (/iphone/.test(userAgent));
2033		var iPadUser = (/ipad/.test(userAgent) || (/macintosh/.test(userAgent) && navigator.maxTouchPoints > 1));
2034		var safariUser = (/^(?!.*(brave|chrome|crios|duckduckgo|edgeios|firefox|fxios|opios|ucbrowser|yabrowser)).*safari.*$/.test(userAgent));
2035
2036		if (safariUser && (iPhoneUser || iPadUser)) {
2037			// Update the UI to notify the user they can install PWA
2038			pwaShowInstallationOption();
2039
2040			// Instructions
2041			var modals = document.querySelectorAll('.js-diks-apps-pwa-ios-instructions').forEach(function(element) {
2042				// Position on screen based on device
2043				if (iPhoneUser) {
2044					element.classList.add('diks-apps__pwa-ios-modal--bottom');
2045				} else if (iPadUser) {
2046					element.classList.add('diks-apps__pwa-ios-modal--top');
2047				}
2048			});
2049
2050			// Handle modal instructions from installation button
2051			document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) {
2052				button.addEventListener('click', (e) => {
2053					// Show first modal
2054					document.querySelector('.js-diks-apps-pwa-ios-instructions').classList.toggle('diks-apps__pwa-ios-modal--is-visible');
2055					dataLayer.push({
2056						'event': 'PWA.instructions.shown',
2057						'eventData': 'iOS'
2058					});
2059				});
2060			});
2061		}
2062	}
2063</script>
2063
2064					
2064<script class="coral-script" src="//coral.prod.diks.fi/assets/js/count.js?v=9.3.1.3" defer></script>
vendor: 78 bytes, lines 2064-2065
2064<script src="https://www.google.com/recaptcha/api.js" async defer></script>
2065		
2065<script>
2066		function onSubmitSidebar(token) {
2067			document.getElementById("lianamailer-sidebar").submit();
2068		}
2069		function onSubmitFooter(token) {
2070			document.getElementById("lianamailer-footer").submit();
2071		}
2072		</script>
2072
2073		<style>.grecaptcha-badge { visibility: hidden; }</style>
2074<div id="diks-bc-order-button" style="display: none;"></div>
2075			</body>
2076</html>
2077

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.